Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 527
Tomek Avatar asked Sep 21 '25 02:09

Tomek


2 Answers

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.

like image 139
cdarke Avatar answered Sep 22 '25 17:09

cdarke


Yep is the short answer. You can try it out yourself:

$ (>&1 echo "STDOUT is gone"; >&2 echo "I'm still here") > /dev/null
I'm still here

STDOUT of the parent process [I'm starting a new shell with the braces:()] will be sent to /dev/null, and so will all the children's STDOUT.

like image 39
mana Avatar answered Sep 22 '25 15:09

mana