What is the differences between &> and 2>&1
Solution 1:
Bash's man page mentions there's two ways to redirect stderr and stdout:
&> file
and >& file
. Now, notice that it says both stderr and stdout.
In case of this >file 2>&1
we are doing redirection of stdout (1) to file, but then also telling stderr(2) to be redirected to the same place as stdout ! So the purpose may be the same, but the idea slightly different. In other words "John, go to school; Suzzie go where John goes".
What about preference ? &>
is a bash
thing. So if you're porting a script, that won't do it. But if you're 100% certain your script will be only working on system with bash - then there's no preference
Here's an example with dash
, the Debian Amquist Shell which is Ubuntu's default.
$ grep "YOLO" * &> /dev/null
$ grep: Desktop: Is a directory
grep: Documents: Is a directory
grep: Downloads: Is a directory
grep: Music: Is a directory
grep: Pictures: Is a directory
grep: Public: Is a directory
grep: Templates: Is a directory
grep: Videos: Is a directory
grep: YOLO: Is a directory
grep: bin: Is a directory
As you can see, stderr is not being redirected
To address your edits in the question, you can use if statement to check $SHELL variable and change redirects accordingly
But for most cases > file 2>&1
should work
In more technical terms, the form [integer]>&word
is called Duplicating Output File Descriptor, and is a feature specified by POSIX Shell Command Language standard, which is supported by most POSIX-compliant and Brourne-like shells.
See also What does & mean exactly in output redirection?
Solution 2:
I would generally recommend following the Bourne-again SHell's way of doing things, since bash is arguably the most popular Unix shell out there. Bash typically uses either &>
or 2>&1
. IMHO, neither is "perfect", so I recommend forgetting about that nonsense. Realistically, which one you should use depends on what you are trying to do.
2>&1
merges stderr with stdout, which can be useful if, for example, you want to pipe stderr text. So, for example, if you want to see if a program prints a certain stderr message, but don't want your screen filled with (presumably) unimportant garbage, you could do something like program 2>&1 | grep crashed
, which will search the stdout and stderr from a program called "program" for the word "crashed".
On the other hand, if you don't want a program to print anything at all, you could simply run program &> /dev/null
, which will redirect both stderr and stdout to /dev/null, a special file which magically makes things disappear. Or, if you want to save the output of a program (perhaps to report a bug or something), you could redirect both stderr and stdout to a file: program &> log.txt
will redirect all data to a file called "log.txt". If you wanted to, you could redirect the stdout and stderr via program 2> log.txt > log.txt
or program 2>&1 | cat > log.txt
, both of which would have the same effect as using &>
. If you do something like program 2>&1 > file
, only stdout will be redirected, but stderr can still be piped to another program, such as cat, which could be redirected as shown above. However, typing &>
is easier than any of the above examples, since it involve typing fewer characters (and it's a bit easier for human beings to read). Do note that program 2> log.txt > log.txt
might be more likely to work on non-bash shells.
PS: if you are worried about people using other shells, there's something you can add to be first line of your script called a "magic number", or "shebang". This is essentially a way to make sure other computers (particularly those running Unix-like operating systems) know which program to use to execute a script. Different scripts use different shebangs. A shebang for a bash script looks like this:
#!/bin/bash
If you use the above as the first line of a given script, bash will generally be used to execute said script. This will make it much more difficult for someone to accidentally execute the script with the wrong shell.
PS: I'm not going to lie: up till now, I didn't know one could use >&
, but, as far as bash goes, it seems to do the same as &>
. You learn something new everyday.