Redirecionamento e descritores de arquivo. (File descriptor)

A tecnologia mais underrated que você já viu.

Você a esse ponto deve saber que você pode escrever em um arquivo, ou fazer pipe de entrada/saída de um programa para o outro. Ótimo, mas essa é só a ponta do iceberg. Isso só acontece porque o terminal, quando você usa o ">" ou "|", ele está fazendo um redirecionamento de descritores de arquivo. O pipe:

$ comando1 | comando2

Ele está redirecionando o stdout do comando1 para stdin do comando2. O stdout é a saída padrão dos comandos, o texto que iria para o terminal, se não fosse o pipe, enquanto o stdin é a entrada padrão, era o que você escreveria no terminal, se não fosse o pipe. Então, você pode dizer que o comando1 está "emulando você" escrevendo, ou melhor, programas não necessariamente sabem quando que é um humano digitando a entrada, ou um programa. E quando você usa o ">", você está redirecionando o stdout para um arquivo, em modo de escrita, o ">>" seria em modo append (escrever, mas sem apagar o que estava antes), e o "<" é em modo de leitura. Aliás, a sintaxe certa do redirecionamento é:

$  comando1 [numero]<<arquivo ou &<numero>> [numero]>[>]<arquivo ou &<numero>>

(Tudo que está entre polchetes ([]), isso significa que é opcional, enquanto tudo que está entre "<>" é obrigatório).

Quando o ">" ou ">>" não vem depois de um numero, ele assume que esse número seja 1 (o stdout), enquanto o "<" assume o 0 (o stdin). Mas o que são exatamente esses números? Esses números são os descritores de arquivo. Quando um programa abre algo pra leitura ou escrita, ele identifica esse arquivo por um identificador numeral, que não necessariamente é um arquivo. O shell abre 3 arquivos pro programa por padrão:

Uma coisa muito comum é usuários usarem '2>&1' pra poder ler algum log de erro com o less(1) ou salvar tudo num arquivo só. Quando você faz isso, você está redirecionando o que sai do stderr para o stdout do mesmo processo (Você também pode fazer '1>&0' pra fazer um loopback), mas uma coisa que poucos usuários sabem é que você não está limitado a só esses 3 descritores. Em uma compilação de kernel linux padrão, o descritor pode ser aberto entre os números 0-1023, mas o programa precisa ser programado para aceitar esses descritores vindos do shell (geralmente, esses outros são usados para abrir arquivos com o open(2)), mas isso pode ser útil pra quando você tiver escrevendo um programa. O AWK aceita você escrever de outros descritores além dos descritores padrão, e tem até um programa chamado pipexec para ajudar a criar pipes mais complexos.

Named pipes.

Os pipes que você estava brincando antes se chamam anonymous pipes, mas existem outros pipes pra processamentos mais complexos. Eles se chamam named pipes, pipes nomeados. Eles são apenas arquivos que você cria com um programa/comando chamado mkfifo. Eles funcionam exatamente igual aos pipes, só que você vai usar redirecionamento ao invés de simples pipes, e eles são half-duplex, isso significa que você pode abrí-lo pra leitura ou escrita, mas não os dois ao mesmo tempo. São uteis quando você precisa lidar com programas que usam arquivos como argumentos. Por exemplo:

$ mkfifo hello.fifo world.fifo
$ ls
hello.fifo  world.fifo
$ echo -n "Hello, " > hello.fifo & #colocando em background pra não travar o terminal
$ echo "World!" > world.fifo &
$ cat hello.fifo world.fifo
Hello, World!
$ _