Search code examples
bashunixprocessstdoutstderr

stdout and stderr redirection in child process


If I run a Bash script like this:

./script.sh 2>&1

stderr will be redirected to stdout.

If the script calls some tool inside (e.g. ls) or spawns a new process, will these child processes have their stderr also redirected to stdout?


Solution

  • Creating a child process on UNIX/Linux uses a procedure generically known as a fork. What this does is to copy almost the entire process address space of the current process (program code, data, almost everything) to the child. The Process IDentifier (PID) is different in the child, but almost everything else is the same.

    One of the items in a process which is copied is the file descriptor table. This is like an array. There is an entry for each file which is open, and by convention the first three, 0, 1, 2, are the standard streams, stdin, stdout, stderr. That explains the numbers used in 2>&1. When we do redirection, it is these three entries that are changed in the child. That is done by the shell, since at this stage our child process is another shell process.

    Now comes the magic part, generically known as exec. If we want to run a different program, like ls, we can switch programs within the process. So now the new program starts from the beginning, but certain core items are retained. Things like the user, group, current directory, umask, and the file descriptor table are all retained for use by the new program.

    So, if the file descriptor table was altered previously, the new program inherits those changes. There is nothing to stop the program from overriding those settings and using different files, but that is rarely done.

    All this behaviour is by default. Programs can change which file descriptors and other items are retained across the fork/exec boundary, but they usually don't.