Além da documentação apontada por jordanm, quero ter certeza de corrigir um equívoco ilustrado em sua pergunta - o programa executado não lida com redirecionamentos. É quase nem mesmo ciente deles. O shell lida com redirecionamentos.
Um programa é iniciado com três arquivos abertos: stdin (# 0), stdout (# 1) e stderr (# 2). Se você acabou de executar um programa a partir do seu prompt de shell, estes serão conectados ao seu dispositivo terminal, assim o programa lê o que você digita (stdin), e imprime saída (stdout) e erros (stderr) para o seu terminal.
Como exemplo, apenas corro cat
em um terminal (que tty
diz é /dev/pts/31
). Posso verificar quais arquivos foram abertos com lsof
:
$ lsof -a -p 'pidof cat' -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
cat 21257 anthony 0u CHR 136,31 0t0 34 /dev/pts/31
cat 21257 anthony 1u CHR 136,31 0t0 34 /dev/pts/31
cat 21257 anthony 2u CHR 136,31 0t0 34 /dev/pts/31
De fato, podemos ver que o terminal está aberto para todos os três. Agora, em vez disso, vamos tentar uma invocação de gato um pouco boba: cat < /dev/zero > /dev/null 2>/dev/full
, que está redirecionando os três:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
cat 21838 anthony 0r CHR 1,5 0t0 1030 /dev/zero
cat 21838 anthony 1w CHR 1,3 0t0 1028 /dev/null
cat 21838 anthony 2w CHR 1,7 0t0 1031 /dev/full
O shell implementou esses redirecionamentos passando os três dispositivos como stdin, stdout e stderr (em vez do terminal). O shell implementa de forma semelhante os tubos. Vamos tentar cat | dd > /dev/null
(um cachimbo bastante bobo, de fato):
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
cat 22507 anthony 0u CHR 136,31 0t0 34 /dev/pts/31
cat 22507 anthony 1w FIFO 0,8 0t0 56081395 pipe
cat 22507 anthony 2u CHR 136,31 0t0 34 /dev/pts/31
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dd 22508 anthony 0r FIFO 0,8 0t0 56081395 pipe
dd 22508 anthony 1u CHR 136,31 0t0 34 /dev/null
dd 22508 anthony 2u CHR 136,31 0t0 34 /dev/pts/31
Observe como o shell abriu um pipe e o usou para conectar o stdout de cat
ao stdin de dd
. Além disso, como ele conectou o stdout de dd
a /dev/null
.
Os comandos que estão sendo executados não estão realmente conscientes dos redirecionamentos. Eles apenas usam stdin, stdout, stderr normalmente. Todos poderiam ser o terminal, ou poderiam ser redirecionados para / de um arquivo, um dispositivo ou talvez um canal para outro programa. Ou até mesmo um socket de rede, se o seu shell suportar isso.
Até mesmo os pipelines mais ridiculamente complicados são na verdade apenas instruções para o shell sobre como conectar esses três identificadores de arquivos antes de executar o programa.
(NOTA: Alguns programas se comportam de maneira diferente no caso de um deles estar conectado a um terminal, mas normalmente é mais amigável no uso interativo. Por exemplo, ls
alterna para saída de coluna única e sem cor Quando o stdout não é um terminal - que geralmente é o que você quer se você está prestes a passá-lo para outro programa. Alguns programas lidam com o prompt diferente se o stdin não for um terminal. E assim por diante.