O que é uma explicação simples de como os pipes funcionam no Bash?

Costumo usar pipes no Bash, por exemplo:

dmesg | less 

Embora eu saiba o que isso gera, é preciso dmesg e me permite percorrê-lo com less , eu não entendo o que o | está fazendo. É simplesmente o oposto de?

  • Existe uma explicação simples ou metafórica para o que | faz?
  • O que acontece quando vários tubos são usados ​​em uma única linha?
  • O comportamento dos pipes é consistente em todos os lugares em que aparece em um script Bash?

    Um pipe Unix conecta o descritor de arquivo STDOUT (saída padrão) do primeiro processo ao STDIN (input padrão) do segundo. O que acontece então é que quando o primeiro processo grava em seu STDOUT, essa saída pode ser imediatamente lida (a partir de STDIN) pelo segundo processo.

    Usando vários tubos não é diferente do que usar um único tubo. Cada pipe é independente e simplesmente vincula STDOUT e STDIN dos processos adjacentes.

    Sua terceira pergunta é um pouco ambígua. Sim, os pipes, como tal, são consistentes em todos os lugares em um script bash. No entanto, o caractere de pipe | pode representar coisas diferentes. Tubo duplo ( || ), representa o operador “ou”, por exemplo.

    Todo processo padrão no Unix possui pelo menos três descritores de arquivos , que são como interfaces :

    • Saída padrão, que é o local onde o processo imprime seus dados (na maioria das vezes o console, ou seja, sua canvas ou terminal).
    • Entrada padrão, que é o local de onde obtém seus dados (na maioria das vezes pode ser algo semelhante ao seu teclado).
    • Erro padrão, que é o local onde os erros e, às vezes, outros dados fora de banda ocorrem. Não é interessante agora porque os tubos normalmente não lidam com isso.

    O pipe conecta a saída padrão do processo à esquerda para a input padrão do processo da direita. Você pode pensar nisso como um programa dedicado que cuida de copiar tudo o que um programa imprime e alimentá-lo para o próximo programa (aquele após o símbolo do pipe). Não é exatamente isso, mas é uma analogia adequada o suficiente.

    Cada pipe opera exatamente em duas coisas: a saída padrão vinda de sua esquerda e o stream de input esperado à sua direita. Cada um desses poderia ser anexado a um único processo ou outro bit do pipeline, que é o caso em uma linha de comando multi-pipe. Mas isso não é relevante para o funcionamento real do tubo; cada tubo faz o seu próprio.

    O operador de redirecionamento ( > ) faz algo relacionado, mas mais simples: por padrão, envia a saída padrão de um processo diretamente para um arquivo. Como você pode ver, não é o oposto de um cano, mas sim complementar. O oposto de > é sem surpresa < , o que leva o conteúdo de um arquivo e o envia para a input padrão de um processo (pense nele como um programa que lê um byte de arquivo por byte e o digita em um processo para você).

    No Linux (e no Unix em geral), cada processo tem três descritores de arquivos padrão:

    1. fd # 0 Representa a input padrão do processo
    2. fd # 1 Representa a saída padrão do processo
    3. fd # 2 Representa a saída de erro padrão do processo

    Normalmente, quando você executa um programa simples, esses descritores de arquivos são configurados da seguinte forma:

    1. a input padrão é lida no teclado
    2. A saída padrão é configurada para ser o monitor
    3. Erro padrão é configurado para ser o monitor também

    O Bash fornece vários operadores para alterar esse comportamento (dê uma olhada nos operadores>, >> e colaborando de tal forma que um usa a saída do outro como sua input. Para facilitar essa colaboração, a Bash fornece ao operador de tubos | . Por favor, note o uso de colaboração em vez de encadeamento . Evitei o uso desse termo, pois, na verdade, um pipe não é seqüencial . Uma linha de comando normal com pipes tem o seguinte aspecto:

      > program_1 | program_2 | ... | program_n 

    A linha de comando acima é um pouco enganosa: o usuário poderia pensar que o programa_2 recebe sua input quando o programa_1 termina sua execução, o que não é correto. De fato, o que o bash faz é lançar TODOS os programas em paralelo e configurar as inputs de saída de maneira que cada programa receba sua input da anterior e entregue sua saída para a próxima (na ordem estabelecida pela linha de comando).

    A seguir, um exemplo simples de Criando pipe em C de criação de um canal entre um processo pai e filho. A parte importante é a chamada para o pipe () e como o pai fecha o fd 1 (lado da escrita) e como o filho fecha o fd 1 (lado da escrita). Por favor, note que o tubo é um canal de comunicação unidirecional . Assim, os dados só podem fluir em uma direção: fd 1 para fd [0]. Para mais informações, consulte a página de manual do pipe ().

     #include  #include  #include  int main(void) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n"; char readbuffer[80]; pipe(fd); if((childpid = fork()) == -1) { perror("fork"); exit(1); } if(childpid == 0) { /* Child process closes up input side of pipe */ close(fd[0]); /* Send "string" through the output side of pipe */ write(fd[1], string, (strlen(string)+1)); exit(0); } else { /* Parent process closes up output side of pipe */ close(fd[1]); /* Read in a string from the pipe */ nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); printf("Received string: %s", readbuffer); } return(0); } 

    Por último, mas não menos importante, quando você tem uma linha de comando no formulário:

     > program_1 | program_2 | program_3 

    O código de retorno das linhas inteiras é definido para o último comando. Neste caso, program_3. Se você gostaria de obter um código de retorno intermediário, você deve definir o pipefail ou obtê-lo do PIPESTATUS .

    Um pipe leva a saída de um processo, por saída quero dizer a saída padrão ( stdout no UNIX) e passa-o na input padrão (stdin) de outro processo. Não é o oposto do simples redirecionamento correto > que tem como objective redirect uma saída para outra saída.

    Por exemplo, pegue o comando echo no Linux, que é simplesmente imprimir uma string passada no parâmetro na saída padrão. Se você usa um redirecionamento simples como:

     echo "Hello world" > helloworld.txt 

    o shell redirectá a saída normal inicialmente destinada a ser stdout e a imprimirá diretamente no arquivo helloworld.txt .

    Agora, pegue este exemplo que envolve o pipe:

    ls -l | grep helloworld.txt

    A saída padrão do comando ls será mostrada na input do grep, então como isso funciona?

    Programas como o grep quando estão sendo usados ​​sem argumentos, estão simplesmente lendo e esperando que algo seja passado em sua input padrão (stdin) . Quando eles pegam algo, como a saída do comando ls, o grep age normalmente encontrando uma ocorrência do que você está procurando.

    • | coloca o STDOUT do comando no lado esquerdo ao STDIN do comando do lado direito.

    • Se você usa vários canais, é apenas uma cadeia de tubos. A saída dos primeiros comandos é configurada para input de segundo comando. A saída dos segundos comandos é configurada para a próxima input de comandos. E assim por diante.

    • Está disponível em todos os intérpretes de comandos baseados em Linux / viúvas.

    O operador de pipe pega a saída do primeiro comando e o canaliza para o segundo, conectando stdin e stdout. No seu exemplo, em vez da saída do comando dmesg indo para stdout (e lançando-o no console), ele está indo direto para o seu próximo comando.

    Tubos são muito simples assim.

    Você tem a saída de um comando. Você pode fornecer essa saída como input em outro comando usando pipe. Você pode canalizar quantos comandos quiser.

    ex: ls | grep my | arquivos grep

    Isso primeiro lista os arquivos no diretório de trabalho. Esta saída é verificada pelo comando grep para a palavra “my”. A saída disso agora está no segundo comando grep que finalmente procura a palavra “arquivos”. É isso aí.

    Se você tratar cada comando unix como um módulo independente,
    mas você precisa deles para conversar um com o outro usando o texto como uma interface consistente ,
    Como pode ser feito?

     cmd input output echo "foobar" string "foobar" cat "somefile.txt" file *string inside the file* grep "pattern" "a.txt" pattern, input file *matched string* 

    Você pode dizer | é uma metáfora para passar o bastão em uma maratona de revezamento.
    É mesmo em forma de um!
    cat -> echo -> less -> awk -> perl é análogo ao cat | echo | less | awk | perl cat | echo | less | awk | perl cat | echo | less | awk | perl .

    cat "somefile.txt" | echo
    cat passa sua saída para o echo usar.

    O que acontece quando há mais de uma input?
    cat "somefile.txt" | grep "pattern"
    Existe uma regra implícita que diz “passar como arquivo de input em vez de padrão ” para o grep .
    Você desenvolverá lentamente o olho para saber qual parâmetro é qual experiência.