Como o pipe funciona nos comandos bash?

Como o pipe funciona nos comandos bash?

Acontece alguma coisa simbólica no encadeamento de comandos bash por meio de um pipe ou é tudo computação-pass-compute-pass?

Por exemplo, em head t.txt -n 5 | tail -n 2, está head t.txt -n 5sendo computado e depois tail -n 2executado. Ou primeiro há alguma abstração para dizer ao shell que as linhas 3 a 5 devem ser lidas? Pode não fazer diferença neste exemplo, mas acho que pode em outros cenários.

Responder1

O shell usa a pipe(2)chamada do sistema para criar um buffer limitado no kernel com dois descritores de arquivo, um para permitir que os processos gravem no buffer e outro para permitir que os processos leiam do buffer.

Considere um caso simples:

$ p1 | p2

Nesse caso, conceitualmente, o shell cria o pipe mencionado acima, fork()s, o filho conecta seu fluxo de saída padrão à extremidade de gravação do pipe e, em seguida, o filho exec()s p1. Em seguida, o shell fork()s novamente, o filho conecta seu fluxo de entrada padrão à extremidade de leitura do pipe e, em seguida, o exec()filho p2. (Eu digoconceitualmenteporque os shells podem fazer as coisas em ordens diferentes, mas a ideia é a mesma.)

Nesse ponto, p1e p2estão sendo executados simultaneamente. p1irá gravar no pipe e o kernel copiará os dados gravados no buffer. p2irá ler do pipe e o kernel copiará os dados lidos do buffer. Se o pipe ficar cheio, o kernel bloqueará p1sua chamada write()até que p2leia algo do pipe, liberando algum espaço. Se o canal estiver vazio, o kernel bloqueará p2sua chamada read()até p1gravar mais dados no canal.

Responder2

Dos dois modelos que você sugere. computar-passar-compute-pass é o mais próximo. O shell apenas conecta os processos. Não sabe nada do que estão fazendo.

Exceto, A ordem de execução é indefinida. Eles efetivamente funcionam ao mesmo tempo. No entanto, o da esquerda deve gerar bytes antes que o da direita os insira. Os dados fluem da esquerda para a direita. Os dados fluem do primeiro comando, saem de seu padrão de saída, então fluem para o padrão de entrada, do próximo processo, onde são processados, então saem de seu padrão de saída, onde podem ser canalizados para outro processo, etc. , etc etc.

Se não houver redirecionamento >, <etc. ou leitura de um arquivo. Então fica assim.

         ┌───────────┐ ┌───────────┐ ┌─────────────┐
Terminal⇨│Process one│⇨│Process two│⇨│Process Three│⇨Terminal
         └───────────┘ └───────────┘ └─────────────┘

informação relacionada