Bash & Shell Scripting DISCUSSION

Why does the order of stdout and stderr redirections change what my Bash script writes to a log file?

Started by khuongnghia Bash redirectionstderr to stdoutfile descriptorslog both streamstee
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Why does the order of stdout and stderr redirections change what my Bash script writes to a log file?

khuongnghia Bash & Shell Scripting Forum
#1

I run a build from a script and want everything in one log. make > build.log 2>&1 captures both normal output and errors, but make 2>&1 > build.log still prints the errors on the terminal. I have also seen &> build.log and 2>&1 | tee build.log.

What does 2>&1 literally mean, why does the order matter, and which form should I use?

Community replies 5

Re: Why does the order of stdout and stderr redirections change what my Bash script writes to a log file?

#2

Every process starts with three open file descriptors: 0 is standard input, 1 is standard output, 2 is standard error. > file is short for 1> file, and 2> file redirects errors. 2>&1 means "make descriptor 2 a copy of whatever descriptor 1 refers to right now". The & is what marks the 1 as a descriptor; 2>1 without it would write errors to a file named 1.

Re: Why does the order of stdout and stderr redirections change what my Bash script writes to a log file?

#3

The shell applies redirections left to right, and the copy is taken at that moment; it is not a lasting link. In make > build.log 2>&1, descriptor 1 is pointed at the file first, then 2 is made a copy of 1, so both go to the file. In make 2>&1 > build.log, descriptor 2 is copied from 1 while 1 is still the terminal, and only afterwards is 1 moved to the file. Errors stay on the terminal.

Pipes are set up before the redirections of a command, which is why make 2>&1 | tee build.log does send both streams into the pipe.

Re: Why does the order of stdout and stderr redirections change what my Bash script writes to a log file?

#4

The shorter spellings are Bash extensions. &> build.log is the same as > build.log 2>&1, &>> appends, and |& is short for 2>&1 |. They do not work in a plain POSIX sh such as dash, so in scripts that start with #!/bin/sh write the long form.

Other useful combinations: cmd > out.log 2> err.log for separate files, cmd 2> /dev/null to discard errors, cmd >> run.log 2>&1 to append both, and echo "warning: low disk" >&2 to write your own messages to standard error.

Re: Why does the order of stdout and stderr redirections change what my Bash script writes to a log file?

#5

Do not point both streams at the same file separately, as in cmd > all.log 2> all.log. That opens the file twice with two independent write positions, and the streams overwrite each other's text. With 2>&1 both descriptors share one open file and one position.

Even then, the order of lines in the log may differ from what you see on a terminal. Many programs buffer standard output in blocks when it is not a terminal, but write standard error immediately, so error lines can appear earlier in the file than the output that preceded them.

Re: Why does the order of stdout and stderr redirections change what my Bash script writes to a log file?

#6

To log everything a script does without touching each command, redirect the script's own descriptors once near the top: exec >> myjob.log 2>&1. Every later command inherits them. To keep seeing the output while logging it, use exec > >(tee -a myjob.log) 2>&1, which relies on Bash process substitution.

When a pipeline's success matters, remember that the exit status of make 2>&1 | tee build.log is that of tee. Check ${PIPESTATUS[0]} or enable set -o pipefail to see whether make failed.

TEP COMMUNITY