Como AlexP explicou nos comentários, os comandos em um pipeline são executados em paralelo . Você parece estar convencido de que isso não é verdade; por favor, esqueça este equívoco, você não será capaz de entender o que está acontecendo, desde que você não abra sua mente.
Como os processos estão sendo executados em paralelo, a sequência de operações depende do tempo exato e pode não ser reproduzível de uma execução para a próxima.
Tomando seu primeiro exemplo, os seguintes comandos são executados em paralelo:
-
seq 1 12773
-
tee /dev/null
-
wc -l > tmp.txt
(uma substituição de processo também cria um canal e executa o comando em paralelo) -
head -$((0x'openssl rand -hex 7' % 'cat tmp.txt' + 1))
- envolve três comandos diferentes ehead
começa depois queopenssl
ecat
saíram -
tail -1
Como wc -l > tmp.txt
e cat tmp.txt
são executados em paralelo, é imprevisível quando cat tmp.txt
será executado em relação à saída de wc
:
- Ele pode ser executado antes que o redirecionamento para
tmp.txt
seja executado e, ou pegar o arquivo de uma execução anterior, se houver, ou reclamar que o arquivo não existe de outra forma. - Pode ser executado após o redirecionamento ser realizado, mas antes que
wc
produza qualquer saída; Nesse caso, o arquivo está vazio, pois o redirecionamento trunca o arquivo. - Pode ser executado enquanto
wc
está produzindo saída e seleciona apenas o início da saída. Na maioria dos sistemas,wc
produz sua saída atomicamente (porque é muito curto), então isso não acontecerá. - Pode ser executado depois que
wc
terminar de produzir a saída.
Experimentalmente, recebo os mesmos resultados que você (em uma máquina Linux executando o kernel 3.16 que, de outra maneira, é mais ociosa): com seq 1 12773
, cat tmp.txt
seleciona a saída de wc
; com seq 1 12774
, cat tmp.txt
seleciona um arquivo vazio. Então, por que há uma diferença entre 12773 e 12774, mas os resultados são bastante confiáveis abaixo desse valor?
$ seq 1 12774 | wc -c
65538
Há um limite em 65536 bytes e esse valor é a capacidade do buffer de tubo . O comando head …
é lento para iniciar, porque ele precisa executar openssl
e cat
até a conclusão primeiro. Enquanto está sendo iniciado, o comando anterior no pipeline grava no buffer de tubulação. Quando o buffer de pipe fica cheio, o comando anterior tem que parar. Com números até 12773, o buffer de pipe nunca é preenchido, então, com toda a probabilidade seq
termina de ser executado antes de openssl
(tem muito menos trabalho a fazer) e wc
tem tempo para gravar sua saída. Mas com números maiores que 12774, o buffer do tubo é preenchido; então tee
está preso escrevendo na saída que vai para head …
e não termina de gravar a saída em wc
ainda. Enquanto isso, cat
é executado com um arquivo vazio.
Quando você adiciona mais canais, cada um tem seu próprio buffer, portanto, há mais espaço antes de tee
parar.