Why does
echo "hello world" | cat
works while
cat < echo "hello world"
does not? My (incorrect) intuition is that pipe would redirect stdout
to cat
as stdin
.
We have two similar but different things
A pipeline
echo "hello world" | cat # This is a pipeline
The pipe control operators (|
and |&
) connect the output of a command to the input of the following one in the pipeline. So the first example works, the output of the echo
command, "Hello word", is connected with the input of the following cat
command, that assumes the standard input as input file if not else specified. Indeed we can read from man cat
:
cat - concatenate files and print on the standard output
and below the example with the simple invocation of cat
cat Copy standard input to standard output
A redirection, or better an attempt of input redirection <
cat < echo "hello world" # This is an attempt of redirection
In this case cat
command is taking its input from the standard input that you redirect with the operator <
from the file on the right side of <
... that is not a file. This is because it doesn't work.
From the redirection section of the man bash
Redirecting Input
Redirection of input causes the file whose name results from the expansion of word to be opened for reading on file descriptor n, or the standard input (file descriptor 0) if n is not specified.
In bash it works for different reasons
cat <(echo "hello world")
Process Substitution
Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files. It takes the form of
<(list)
or>(list)
. The process list is run with its input or output connected to a FIFO or some file in/dev/fd
. The name of this file is passed as an argument to the current command as the result of the expansion. If the>(list)
form is used, writing to the file will provide input for list. If the<(list)
form is used, the file passed as an argument should be read to obtain the output of list.
cat <<< $(echo "hello world")
Here Strings
The word undergoes brace expansion, tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, and quote removal. Path-name expansion and word splitting are not performed. The result is supplied as a single string to the command on its standard input.
References
man bash
and search for redirection, pipeline, Here Strings and Process substitutionman cat
just because we use it...That stream reads from files. >
is out to a file and <
is in from a file. Demonstration:
First echo "HELLO HELLO HELLO" > HELLO.txt
and then cat < HELLO.txt
gets you output
HELLO HELLO HELLO
Kinda useless since the output already goes where you'd want, but another example with the same HELLO.txt is cat < HELLO.txt >&1
explicitly directing cat
's output to STDOUT.
More usefully, you sometimes find file descriptor 2's output (STDERR) being redirected with commands like
grep somepattern /path/to/a_bunch_of_files/* 2>&1 >> alloutput.txt
The 2>&1
stream directs errors to standard output. Then all standard output is streamed to alloutput.txt. This would put error output in the file with standard output.
cat <<< "hello word"
, if interested you can doman bash
and search forHere Strings
.