Consegui descobrir usando strace -f e escrevendo uma pequena prova de conceito em C.
Parece que o bash apenas manipula os descritores de arquivos no processo filho antes de chamar execve como eu pensava.
Veja como ls -la > diroutput.log funciona (aproximadamente):
- chamadas do bash
fork(2) - processo bash bifurcado vê o redirecionamento de saída e abre o arquivo
diroutput.logusingopen(2). - o processo bash bifurcado substitui o descritor de arquivo
stdoutusandodup2(2)syscall - bash chama
execve(2)para substituir sua imagem executável porls, que então herda a configuraçãostdout
Os syscalls relevantes são assim ( 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