Pipe is used to pass output to another program or utility.
Redirect is used to pass output to either a file or stream.
Example: thing1 > thing2
vs thing1 | thing2
thing1 > thing2
- Your shell will run the program named
thing1
- Everything that
thing1
outputs will be placed in a file called thing2
. (Note - if thing2
exists, it will be overwritten)
If you want to pass the output from program thing1
to a program called thing2
, you could do the following:
thing1 > temp_file && thing2 < temp_file
which would
- run program named
thing1
- save the output into a file named
temp_file
- run program named
thing2
, pretending that the person at the keyboard typed the contents of temp_file
as the input.
However, that's clunky, so they made pipes as a simpler way to do that. thing1 | thing2
does the same thing as thing1 > temp_file && thing2 < temp_file
EDIT to provide more details to question in comment:
If >
tried to be both "pass to program" and "write to file", it could cause problems in both directions.
First example: You are trying to write to a file. There already exists a file with that name that you wish to overwrite. However, the file is executable. Presumably, it would try to execute this file, passing the input. You'd have to do something like write the output to a new filename, then rename the file.
Second example: As Florian Diesch pointed out, what if there's another command elsewhere in the system with the same name (that is in the execute path). If you intended to make a file with that name in your current folder, you'd be stuck.
Thirdly: if you mis-type a command, it wouldn't warn you that the command doesn't exist. Right now, if you type ls | gerp log.txt
it will tell you bash: gerp: command not found
. If >
meant both, it would simply create a new file for you (then warn it doesn't know what to do with log.txt
).
The &
in 2>&1
simply says that the number 1
is a file descriptor and not a file name. In this case the standard output file descriptor
.
If you use 2>1
, then this would redirect errors to a file called 1
but if you use 2>&1
, then it would send it to the standard output stream
.
This &>
says send both, standard output
and standard error
, somewhere. For instance, ls <non-existent_file> &> out.file
. Let me illustrate this with an example.
Setup:
Create a file koko
with the following content:
#!bin/bash
ls j1
echo "koko2"
Make it executable: chmod u+x koko
Now note that j1
doesn't exist
Now run ./koko &> output
run cat output
and you will see
ls: cannot access 'j1': No such file or directory
koko2
Both, standard error
(ls: cannot access 'j1': No such file or directory
) and standard output
(koko2
), were sent to the file output
.
Now run it again but this time like so:
./koko > output
Do cat output
and you will only see the koko2
like. But not the error output from the ls j1
command. That will be sent to the standard error
which you will see in your terminal.
Important note thanks to @Byte Commander:
Note that in command >file 2>&1
the order of the redirection is important. If you write command 2>&1 >file
instead (which is normally not what you want), it will first redirect the command's stdout
to the file and after that redirect the command's stderr
to its now unused stdout
, so it will show up in the terminal and you could pipe it or redirect it again, but it will not be written to the file.
Best Answer
When you run
<command> 2>&1 > file.txt
stderr is redirected by2>&1
to where stdout currently goes, your terminal. After that, stdout is redirected to the file by>
, but stderr is not redirected with it, so stays as terminal output.With
<command> > file.txt 2>&1
stdout is first redirected to the file by>
, then2>&1
redirects stderr to where stdout is going, which is the file.It may seem counter intuitive to start with, but when you think of the redirections in this way, and remember that they are processed from left to right it makes much more sense.