Em que ordem os comandos canalizados são executados?

85

Eu nunca pensei sobre como o shell realmente executa comandos canalizados. Sempre me disseram que o "stdout de um programa fica canalizado para o stdin de outro", como uma maneira de pensar em pipes. Então, naturalmente, eu pensei que, no caso de dizer, A | B, A seria executado primeiro, depois B obteria o stdout de A e usaria o stdout de A como entrada.

Mas notei que quando as pessoas pesquisam por um processo específico em ps, elas incluem grep -v "grep" no final do comando para garantir que o grep não apareça na saída final. Isso significa que no comando ps aux | grep "bash" | grep -v "grep", o que significa que o ps sabia que o grep estava rodando e, portanto, está na saída do ps. Mas se o ps terminar de rodar antes de sua saída ser canalizada para o grep, como ele sabia que o grep estava rodando?

flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY          TIME CMD
3773 pts/0    00:00:00 bash
3784 pts/0    00:00:00 ps
3785 pts/0    00:00:00 grep
    
por action_potato 28.04.2012 / 05:16

4 respostas

60

Os comandos canalizados são executados simultaneamente. Quando você executa ps | grep … , é a sorte do sorteio (ou uma questão de detalhes do funcionamento do shell combinada com o agendamento de afinação profunda nas entranhas do kernel) para saber se ps ou grep começa primeiro, e em qualquer caso continuam a executar concorrentemente.

Isso é muito comumente usado para permitir que o segundo programa processe os dados conforme eles saem do primeiro programa, antes que o primeiro programa tenha concluído sua operação. Por exemplo

grep pattern very-large-file | tr a-z A-Z

começa a exibir as linhas correspondentes em letras maiúsculas, mesmo antes de grep terminar de percorrer o arquivo grande.

grep pattern very-large-file | head -n 1

exibe a primeira linha correspondente e pode parar o processamento antes que grep termine de ler seu arquivo de entrada.

Se você ler em algum lugar que programas encadeados executados em seqüência, elimine este documento. Os programas canalizados são executados simultaneamente e sempre têm.

    
por 30.04.2012 / 03:37
47

A ordem em que os comandos são executados, na verdade, não importa e não é garantida. Deixando de lado os detalhes arcanos de pipe() , fork() , dup() e execve() , o shell primeiro cria o canal, o canal para os dados que fluirão entre os processos e, em seguida, cria os processos com as extremidades de o tubo conectado a eles. O primeiro processo executado pode bloquear a espera pela entrada do segundo processo ou bloquear a espera pelo segundo processo para iniciar a leitura dos dados do canal. Essas esperas podem ser arbitrariamente longas e não importam. Qualquer que seja a ordem em que os processos são executados, os dados são transferidos e tudo funciona.

    
por 28.04.2012 / 07:16
23

Correndo o risco de bater em um cavalo morto, o equívoco parece ser que

    A | B

é equivalente a

    A > temporary_file
    B < temporary_file
    rm temporary_file

Mas, quando o Unix foi criado e as crianças montaram dinossauros para a escola, discos eram muito pequenos, e era comum um comando bastante benigno para consumir todo o espaço livre em um sistema de arquivos. Se B fosse algo como %código%, a saída final do pipeline poderia ser muito menor que o arquivo intermediário. Portanto, o tubo foi desenvolvido, não como um atalho para Primeiro, execute o A e, em seguida, execute B com a entrada do modelo A de saída, mas como uma forma de grep some_very_obscure_string executar simultaneamente com B e elimine a necessidade de armazenar o arquivo intermediário no disco.

    
por 11.07.2014 / 19:26
0

Normalmente, você executa isso no bash. processo trabalhando e iniciando simultaneamente, mas estão sendo executados pelo shell em paralelo. Como isso é possível?

  1. se não for o último comando no pipe, crie um pipe sem nome com um par de soquetes
  2. garfo
  3. no filho, reatribuir stdin / stdout para soquetes, se necessário (para o primeiro processo no pipe, stdin não é reatribuído, o mesmo para o último processo e seu stdout)
  4. no comando EXEC filho especificado com argumentos que varrem o código shell original, mas deixam todos abertos por eles. o ID do processo filho não será alterado porque este é o mesmo processo filho
  5. ao mesmo tempo com filho, mas paralelamente sob o shell principal, vá para a etapa 1.

o sistema não garante a rapidez com que exec será executado e o comando especificado será iniciado. é independente do shell, mas do sistema. Isso é porque:

ps auxww| grep ps | cat

uma vez, mostre o comando grep e / ou ps e o próximo agora. Depende de quão rápido o kernel realmente inicia os processos usando a função exec do sistema.

    
por 05.09.2013 / 09:17

Tags