foo.exe > out.txt 2>&1 will redirect both stdout and stderr to a file.
However foo.exe 2>&1 > out.txt will redirect stdout to a file and stderr to console. Why do they behave differently? Aren't they both saying the same thing (send stderr to stdout and send stdout to file)?
You need to set up the redirection from STDOUT first, and then set the 2>&1 redirection. It redirects STDERR to the place that STDOUT is going.
Related
You can redirect stderr and stdout of a bash command to file using foo > out.txt 2>&1
But, consider: ssh user#host > out.txt 2>&1. In my experience, if a password is needed to connect, the password prompt will be displayed to the screen and not be sent to file.
For a more extreme example, tmux > out.txt 2>&1 fails to redirect anything to file, except for a final [exited] message.
What's going on here, and is it possible to redirect all output?
Have you tried using "| tee out.txt 2>&1" ?
Sorry, didn't understood your question... You need a terminal print and a file output?
I want to start a program and redirect stdout and stderr in one file and stderr to another. I read a lot about using tee but this seems not to work for cmd.
This already works but I need stderr in a second file as well.
programm >> combined.log 2>&1
I have tried sth like this but it didnt work.
program >> combined.log 2>&1 2>> error.log
It would be nice to have your cake and eat it too. That is not always possible. The stderr log can be captured, then appended to the combined log.
program >>combined.log 2>err.log
type err.log >>combined.log
When combining stderr with stdout, why does 2>&1 need to come before a | (pipe) but after a > myfile (redirect to file)?
To redirect stderr to stdout for file output:
echo > myfile 2>&1
To redirect stderr to stdout for a pipe:
echo 2>&1 | less
My assumption was that I could just do:
echo | less 2>&1
and it would work, but it doesn't. Why not?
A pipeline is a |-delimited list of commands. Any redirections you specify apply to the constituent commands (simple or compound), but not to the pipeline as a whole. Each pipe chains one command's stdout to the stdin of the next by implicitly applying a redirect to each subshell before any redirects associated with a command are evaluated.
cmd 2>&1 | less
First stdout of the first subshell is redirected to the pipe from which less is reading. Next, the 2>&1 redirect is applied to the first command. Redirecting stderr to stdout works because stdout is already pointing at the pipe.
cmd | less 2>&1
Here, the redirect applies to less. Less's stdout and stderr both presumably started out pointed at the terminal, so 2>&1 in this case has no effect.
If you want a redirect to apply to an entire pipeline, to group multiple commands as part of a pipeline, or to nest pipelines, then use a command group (or any other compound command):
{ { cmd1 >&3; cmd2; } 2>&1 | cmd3; } 3>&2
Might be a typical example. The end result is: cmd1 and cmd2's stderr -> cmd3; cmd2's stdout -> cmd3; and cmd1 and cmd3's stderr, and cmd3's stdout -> the terminal.
If you use the Bash-specific |& pipe, things get stranger, because each of the pipeline's stdout redirects still occur first, but the stderr redirect actually comes last. So for example:
f() { echo out; echo err >&2; }; f >/dev/null |& cat
Now, counterintuitively, all output is hidden. First stdout of f goes to the pipe, next stdout of f is redirected to /dev/null, and finally, stderr is redirected to stdout (/dev/null still).
I recommend never using |& in Bash -- it's used here for demonstration.
Many of the obligatory redirection links
To add to ormaaj's answer:
The reason you need to specify redirection operators in the proper order is that they're evaluated from left to right. Consider these command lists:
# print "hello" on stdout and "world" on stderr
{ echo hello; echo world >&2; }
# Redirect stdout to the file "out"
# Then redirect stderr to the file "err"
{ echo hello; echo world >&2; } > out 2> err
# Redirect stdout to the file "out"
# Then redirect stderr to the (already redirected) stdout
# Result: all output is stored in "out"
{ echo hello; echo world >&2; } > out 2>&1
# Redirect stderr to the current stdout
# Then redirect stdout to the file "out"
# Result: "world" is displayed, and "hello" is stored in "out"
{ echo hello; echo world >&2; } 2>&1 > out
My answer is by understanding file descriptors. Each process has a bunch of file descriptors: entries to files that are opened. By default, number 0 is for stdin, number 1 is for stdout and number 2 is for stderr.
The i/o redirectors > and < by default connect to their most reasonable file descriptors, stout and stdin. If you re-route stdout to a file (as with foo > bar), on starting process 'foo', the file 'bar' is opened for writing and hooked on file descriptor number 1. If you want only stderr in 'bar', you'd use foo 2> bar which opens file bar and hooks it to the stderr.
Now the i/o redirector '2>&1'. I normally read that as 'put file descriptor 2 to the same as file descriptor 1. While reading the commandline from left to right, you can do the next: foo 1>bar 2>&1 1>/dev/tty. With this, file descriptor 1 is set to the file 'bar', file descriptor 2 is set to the same as 1 (hence 'bar') and after that, file descriptor 1 is set to /dev/tty. The runnning foo is sending its output to /dev/tty and it stderr to the file 'bar'.
Now the pipeline comes in: this does not alter the file descriptors, however, it will connect them between the processes: stdout of the left process ot stdin of the next. Stderr is passed on. Hence, if you like the pipeline to work on stderr only, you use foo 2| bar, which connects stderr of foo to stdin of bar. (I'm not sure what happens with the stdout of foo.)
With the above, if you use foo 2>&1 | bar, since stderr of foo is re-routed to stdout of foo, both stdout and stderr of foo arrive at the stdin of bar.
I was wondering how to redirect stderr to multiple outputs. I tried it with this script, but I couldn't get it to work quite right. The first file should have both stdout and stderr, and the 2nd should just have errors.
perl script.pl &> errorTestnormal.out &2> errorTest.out
Is there a better way to do this? Any help would be much appreciated. Thank you.
perl script.pl 2>&1 >errorTestnormal.out | tee -a errorTestnormal.out > errorTest.out
Will do what you want.
This is a bit messy, lets go through it step by step.
We say what used to go to STDERR will now go STDOUT
We say what used to go to STDOUT will now go to errorTestnormal.out.
So now, STDOUT gets printed to a file, and STDERR gets printed to STDOUT. We want put STDERR into 2 different files, which we can do with tee. tee appends the text it's given to a file, and also echoes to STDOUT.
We use tee to append to errorTestnormal.out, so it now contains all the STDOUT and STDERR output of script.pl.
Then, we write STDOUT of tee (which contains STDERR from script.pl) into errorTest.out
After this, errorTestnormal.out has all the STDOUT output, and then all the STDERR output. errotTest.out contains only the STDERR output.
I had to mess around with this for a while as well. In order to get stderr in both files, while only putting stdout into a single file (e.g. stderr into errors.log and output.log and then stdout into just output.log) AND in the order that they happen, this command is better:
((sh test.sh 2>&1 1>&3 | tee errors.log) 3>&1 | tee output.log) > /dev/null 2>&1
The last /dev/nul 2>&1 can be omitted if you want the stdout and stderr to still be output onto the screen.
I guess in case of the 2nd ">" you try to send the error output of errorTestnormal.out (and not that of script.pl) to errorTest.out.
Most of us know that to redirect STDERR to STDOUT we do 2>&1
We also know about FILE redirection using ">" and process redirection using "|"
What I always wondered about was about the combination of the above two
If you want to redirect both STDERR and STDOUT of prog1 to prog2 you place the 2>&1 prior to the |prog2 pipe. On the other hand, if you are redirecting STDERR and STDOUT of prog1 to a file (file.txt), the 2>&1 goes after the > file.txt.
So I know HOW to do it, I am just wondering WHY it is done like that. To me it seems inconsistent, but I may be looking at it the wrong way
Thanks
They are processed in order.
So if you do
progname 2>&1 1>out.txt
That diverts stderr from the program to the current destination of the program's stdout, which is the stdout stream of the shell, and diverts stdout of the program to out.txt.
if you do
progname 1>out.txt 2>&1
That diverts the stdout of the program to out.txt, then diverts the stderr from the program to the current destination of the program's stdout, which is out.txt.
It helps if you don't think of a pipe as redirection. Using 2>&1, you're redirecting stderr to stdout. Only stdout goes through a pipe. If you redirect stdout before a pipe, then nothing goes through.