Confusion with the redirection of output to 2>&1? - linux

I have checked couple of relevant posts regarding this in stackoverflow and other sources regarding the usage of 2>&1.
Unfortunately so far have not get my head around it completely.
I understand that 2 is the stderr and 1 is the stdout and we are combining with the 2>&1.
But my question is what is difference between:
1. mycommand > /dev/null
2. mycommand 2> /dev/null
3. mycommand > /dev/null 2>&1
I was thinking:
will redirect stdout and stderr to /dev/null
will redirect stderr to /dev/null
will redirect stdout and stderr to /dev/null
Relevant posts:
What does "/dev/null" mean at the end of shell commands)
i/o stream redirection on linux shell. how does the shell process a command with redirection?
What does “> /dev/null 2>&1″ mean? (http://www.xaprb.com/blog/2006/06/06/what-does-devnull-21-mean/)

See this:
mycommand > /dev/null
it will redirect channel 1 (which is stdout) of mycommand to /dev/null
mycommand 2> /dev/null
it will redirect channel 2 (which is stderr) to /dev/null
mycommand > /dev/null 2>&1
it will redirect channel 1 to /dev/null and then bind channel 2 (stderr) to channel 1 (stdout). Both will go into /dev/null
There is another one (just to complete)
mycommand 2>&1 > /dev/null
In this second case, I bind (the child's) stderr to stdout (of the
parent) and then I find the child's stdout to /dev/null. The result is
that you now get the child's stderr output on stdout and the stdout
goes to the file. This is useful for processing stderr in a pipe, for
example. (see this answer)

(errfile doesn't exist)
$ cat errfile
cat: 0652-050 Cannot open errfile.
$ cat errfile > /tmp/stream.out
cat: 0652-050 Cannot open errfile.
$ cat errfile > /tmp/stream.out 2>&1
$ cat /tmp/stream.out
cat: 0652-050 Cannot open errfile.
($ rm /tmp/stream.out)
$ cat errfile 2>&1 > /tmp/stream.out
cat: 0652-050 Cannot open errfile.
$ cat /tmp/stream.out
$
Order is thus important and 2>&1 1>out is different than 1>out 2>&1 due to stream redirection at shell interpretation. You shoud redirect in "reverse" order. stdout > final than source > stdout

Try these to get the differences:
echo "stderr" > /dev/fd/2 | >/dev/null
stderr
echo "stdout" > /dev/fd/1 | >/dev/null
both commands redirected to /dev/null but in first one we're writing to stderr which prints stderr but in second one it prints nothing

1: redirect STDOUT to /dev/null, you use default file descriptor in this case, e.g. command [default]> filename, the default file descriptor is STDOUT.
2: redirect STDERR to /dev/null
3: redirect STDOUT to /dev/null and redirect STDERROR to STDOUT, which means both STDOUT and STDERROR will be redirected to /dev/null
Hope the tips make you clear.
0, 1, 2...9 are file descriptors in bash. 0 stands for stdin, 1 stands for stdout, 2 stands for stderror. 3~9 is spare for any other temporary usage.
Any file descriptor can be redirected to other file descriptor or file by using operator > or >>(append).
Usage: >
Please reference to http://www.tldp.org/LDP/abs/html/io-redirection.html

Related

Write stderr and stdout to one file, but also write stderr to a separate file

I have a shell script whose stdout and stderr I want to write to a logfile. I know that this can be achieved via
sh script.sh >> both.log 2>&1
However, I also want to simultaneously write the stderr to a separate file, "error.log". Is this achievable?
You can use tee to duplicate output to two locations. Combine that with some tricky redirections, and...
script.sh 2>&1 >> both.log | tee -a both.log >> error.log
This redirects stderr to stdout, and then stdout to both.log. stderr remains, and is piped to tee, which copies it to both log files.
For this you need to first switch stdout and stderr, which requires an additional file descriptor:
sh script.sh 3>&2 2>&1 1>&3 3>&-
The last operator closes the auxiliary file descriptor.
After that you can use tee to duplicate the error stream (which is now on stdin) and append it to your error log:
sh script.sh 3>&2 2>&1 1>&3 3>&- | tee -a error.log
And after that you can then direct both stdin and stderr to your combined log:
(sh script.sh 3>&2 2>&1 1>&3 3>&- | tee -a error.log) >> both.log 2>&1
The parentheses around the command are important to capture the error stream of the whole command. Without them only the (empty) error stream of the tee command would be captured and the rest would still go to the terminal.
Note: this does not check wheater the file descriptor 3 was in use (open) before. In bash you can use this to choose a previously unused file descriptor and close it on the last redirection:
sh script.sh {tmpfd}>&2 2>&1 1>&${tmpfd}-

What's the difference between ">/dev/null 2>&1" and "2>/dev/null >&2"

I have a question for redirection.
I always use anycommands > /dev/null 2>&1 when I need not any output. But I have never used anycommands 2> /dev/null >&2
Question: Which one is the best way to expect no outputs? What's the difference between anycommands > /dev/null 2>&1 and anycommands 2> /dev/null >&2
case#1:(echo stdout;echo stderr>&2) >/dev/null 2>&1
stdout(1) is replaced by an fd to /dev/null
stderr(2) descriptor is copied from &1 which now is an fd to /dev/null
result: no output at all
case#2:(echo stdout;echo stderr>&2) 2>&1 >/dev/null
stderr(2) descriptor is copied from &1 which is the default stdout
stdout(1) is replaced by an fd to /dev/null
result: stderr is empty, stdout not shown, stderr on stdout
case#3: (echo stdout; echo stderr >&2) 2> /dev/null >&2
same as case#1, stderr and stdout have switched roles
Effectively, the two are equivalent. cmd > /dev/null 2>&1 connects stdout of the command to /dev/null, and then connects stderr to the same file. cmd 2>/dev/null >&2 connects stderr to /dev/null, and then connects stdout to it. The only difference is in the order in which the two streams are associated with /dev/null, which has no bearing on the status of the command when it is run. In both cases, both streams are redirected to the bit bucket.
If you're using only BASH, use &> to redirect both stdout and stderr. That's the most compact, safe and simple solution.
Regarding your question, the first one is equivalent to &> (it redirects both stdout and stderr to /dev/null.
The second connects stderr to /dev/null and redirects stdout to the new stderr, so it's equivalent to as far as the output is concerned. Just the order of file descriptor operations is reversed.

Redirect stdout and stderr to file and stderr to stdout

The following writes stdout to a logfile and prints stderr:
bash script.sh >> out.log
This again writes both stdout and stderr to a logfile:
bash script.sh >> out.log 2>&1
How to combine both features, so that stdout and stderr are logged to a file and stderr is emailed to my inbox?
bash script.sh 2>&1 >> out.log | tee -a out.log
First, I'm redirecting stdout to file and stderr to stdout (stdout line gets to the out.log file and stderr to pipe).
The tee command prints stdin to both stdout and file (resemblance with the letter T). Thus second, I'm printing the original stderr to both stdout and the out.log file (the -a argument means append).
You can keep stdout in a separate file and stderr in separate file:
0 * * * * bash script.sh > out.log 2> err.log
and then email yourself err.log file.
Here is a working solution:
./myscript.sh &> all.txt 2> stderr.txt
&> all.txt to have both stderr and stdout
2> stderr.txt to have only stderr
And then just do whatever you want with those files, such as email logging for instance!
Using process substitution you can try:
0 * * * * bash script.sh >> out.log 2> >(exec tee >(exec cat >> mail))
Or
0 * * * * bash -c 'exec bash script.sh >> out.log 2> >(exec tee >(exec cat >> mail))'
exec cat >> mail imitates mailing. Replace it with a command that actually does the mailing.

What is the difference between ">" and "&>" in bash?

In bash we have 3 stream types:
0 (STDIN)
1 (STDOUT)
2 (STDERR)
So, while executing some program i can use these streams (e.g. i can redirect them from console to a file or smth like /dev/null, etc):
# only errors from STDERR will be shown, STDOUT will be moved to /dev/null
command > /dev/null
# only STDOUT will be shown, STDERR will be moved to /dev/null
command 2> /dev/null
I saw that some people write
command &> /dev/null
What is the difference between > and &> in bash?
what is the difference between ">" and "&>" in bash?
It's a bashism that redirects both stdout and stderr. It can also be achieved with the more portable:
command > file 2>&1

How to redirect the output of an application in background to /dev/null

I would like to redirect the output generated from a background application in Linux to /dev/null.
I am using kate text editor and it prints all the debug messages on the terminal which I would like to redirect to /dev/null.
Any idea how to do it ?
Thanks
You use:
yourcommand > /dev/null 2>&1
If it should run in the Background add an &
yourcommand > /dev/null 2>&1 &
>/dev/null 2>&1 means redirect stdout to /dev/null AND stderr to the place where stdout points at that time
If you want stderr to occur on console and only stdout going to /dev/null you can use:
yourcommand 2>&1 > /dev/null
In this case stderr is redirected to stdout (e.g. your console) and afterwards the original stdout is redirected to /dev/null
If the program should not terminate you can use:
nohup yourcommand &
Without any parameter all output lands in nohup.out
These will also redirect both:
yourcommand &> /dev/null
yourcommand >& /dev/null
though the bash manual says the first is preferred.

Resources