Unfortunately I've had no luck figuring this out, as everything I find is just on the syntax of redirection, or shallow information about how redirection works.

What I want to know is how bash actually changes stdin/stdout/stderr when you use pipes or redirection. If for example, you execute:

ls -la > diroutput.log

How does it change stdout of ls to diroutput.log?

I assume it works like this:

  • Bash runs fork(2) to create a copy of itself
  • Forked bash process sets it's stdout to diroutput.log using something like freopen(3)
  • Forked bash process runs execve(2) or a similar exec function to replace itself with ls which now uses the stdout setup by bash

But that's just my educated guess.


I was able to figure it out using strace -f and writing a small proof of concept in C.

It appears that bash just manipulates file descriptors in the child process before calling execve as I thought.

Here's how ls -la > diroutput.log works (roughly):

  • bash calls fork(2)
  • forked bash process sees the output redirection and opens the file diroutput.log using open(2).
  • forked bash process replaces the stdout file descriptor using the dup2(2) syscall
  • bash calls execve(2) to replace it's executable image with ls which then inherits the already setup stdout

The relevant syscalls look like this (strace output):

6924  open("diroutput.log", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 
6924  dup2(3, 1)                        = 1 
6924  close(3)                          = 0 
6924  execve("/bin/ls", ["ls", "-la"], [/* 77 vars */]) = 0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.