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 eheadcomeça depois queopensslecatsaí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.txtseja 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
wcproduza qualquer saída; Nesse caso, o arquivo está vazio, pois o redirecionamento trunca o arquivo. - Pode ser executado enquanto
wcestá produzindo saída e seleciona apenas o início da saída. Na maioria dos sistemas,wcproduz sua saída atomicamente (porque é muito curto), então isso não acontecerá. - Pode ser executado depois que
wcterminar 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.