Entendendo UNIX pipes

leandronsp

Leandro Proença

Posted on June 15, 2022

Entendendo UNIX pipes

Basicamente, a todo comando UNIX é atribuído um conjunto de streams, que são canais de comunicação. Ou seja, um comando pode enviar dados para uma stream de saída (STDOUT), ler dados de uma stream de entrada (STDIN) e escrever dados em uma stream de falhas/erros (STDERR).

Cada stream é representada por um número inteiro através de file descriptors:

  • 0: stream de entrada
  • 1: stream de saída
  • 2: stream de erros

UNIX e comunicação de processos

Por padrão, processos no sistema operacional são isolados. Mas para uso real, um processo precisa se comunicar com outros através do envio de mensagens.

Os streams de comunicação são, portanto, uma forma de comunicação entre processos, também chamada de Inter-Process communication, ou IPC.

Redirecionamento do STDOUT

Quando executamos comandos UNIX, a stream padrão de saída é o próprio screen, ou STDOUT.

$ echo 'Olá!'
Enter fullscreen mode Exit fullscreen mode
Olá!
Enter fullscreen mode Exit fullscreen mode

Isto mostra no screen a palavra Olá. Mas podemos redirecionar o output para um arquivo à parte para ser consultado depois. Este redirecionamento deve ser feito com os sinais > (para stdout e stderr) ou < (para stdin).

Em cada sinal deve ser prefixado o número do file descriptor correspondente.

# o stdout 1 está sendo redirecionado para out.log

$ echo 'Olá!' 1> out.log 

### DICA BÔNUS
# Se omitirmos o número do file descriptor, por padrão o UNIX
# entende que é o STDOUT!!!!1
$ echo 'Olá!' > out.log 
Enter fullscreen mode Exit fullscreen mode

Com redirecionamento, o sistema "muda" o comportamento padrão do stream. Neste caso, não vemos mais a palavra sendo enviada para o screen. Precisamos então consultar o arquivo:

$ cat out.log
Enter fullscreen mode Exit fullscreen mode
Olá!
Enter fullscreen mode Exit fullscreen mode

Redirecionamento do STDIN

Vamos imaginar um cenário onde queremos gerar hash de um conteúdo utilizando md5.

O comando md5 recebe um arquivo como input. Como o STDIN por padrão lê do screen (e fica a espera de dados a partir do teclado), podemos redirecionar o STDIN (0) tal como fizemos com o STDOUT (1), de forma que o input seja lido a partir de um arquivo, e não do teclado:

$ echo 'my precious' > rawcontent.txt # redireciona stdout 1
$ md5 0< rawcontent.txt               # redireciona stdin 0
Enter fullscreen mode Exit fullscreen mode
2a5f942537474f69e4bca57711ae6ff2
Enter fullscreen mode Exit fullscreen mode

E o STDERR?

Assim como fazemos para o STDOUT com o sinal >, podemos redirecionar o STDERR (erros ocorridos durante o comando) para outro lugar:

$ md5 rawcontent.txt 2> md5err.log
Enter fullscreen mode Exit fullscreen mode

Nesse caso, como o comando não lança nenhum erro, o arquivo md5err.log está vazio e o output foi enviado para o STDOUT.

$ md5 filenotfound 2> md5err.log
$ cat md5err.log
Enter fullscreen mode Exit fullscreen mode
md5: filenotfound: No such file or directory
Enter fullscreen mode Exit fullscreen mode

Inclusive podemos fazer redirecionamento de todas as saídas no mesmo comando:

$ md5 rawcontent.txt > md5out.log 2> md5err.log
Enter fullscreen mode Exit fullscreen mode

Ou então, fazer com que o STDERR seja redirecionado para o STDOUT:

$ md5 rawcontent.txt > md5out.log 2>&1
Enter fullscreen mode Exit fullscreen mode

UNIX pipelines

E se quisermos continuar criando uma "pipeline" de transformação dos dados, de forma que ao fim do md5, queremos transformar o conteúdo em base64?

Podemos continuar redirecionando "outs e ins" quantas vezes quisermos em múltiplos comandos:

$ echo 'my precious' > rawcontent.txt
$ md5 0< rawcontent.txt > md5content.txt
$ base64 0< md5content.txt
Enter fullscreen mode Exit fullscreen mode
MmE1Zjk0MjUzNzQ3NGY2OWU0YmNhNTc3MTFhZTZmZjIK
Enter fullscreen mode Exit fullscreen mode

Mas esta cadeia de múltiplos comandos ficaria ilegível e difícil de manter. Sem contar que tantos aquivos de redirecionamento vão ficar ocupando espaço de armazenamento o que nos obrigaria a ter uma rotina para apagar tais arquivos.

Podemos recorrer aos pipes anônimos |, ou unnamed pipes, que basicamente redirecionam o stdout de um comando para o stdin do outro comando na sequência.

E diferente dos arquivos de redirecionamento, os pipes anônimos funcionam como file descriptor "temporários" que são apagados ao término do comando.

$ echo 'my precious' | md5 | base64
Enter fullscreen mode Exit fullscreen mode
MmE1Zjk0MjUzNzQ3NGY2OWU0YmNhNTc3MTFhZTZmZjIK
Enter fullscreen mode Exit fullscreen mode

Lindo, não é?

Conclusão

Neste artigo, tentei demonstrar o funcionamento básico de UNIX pipelines, que utilizam pipes anônimos para que diferentes processos possam comunicar entre si.

Este artigo do Marcell Cruz é bastante elucidativo e me ajudou a despertar interesse em dissecar o tema para produzir mais conteúdo de UNIX em pt-BR.

No artigo a seguir mostro como funcionam UNIX named pipes e como isto abre portas para a implementação de um simples background job em Shell script.

Stay tuned!

💖 💪 🙅 🚩
leandronsp
Leandro Proença

Posted on June 15, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related