# UNIX Pipes

Para entendermos UNIX *pipes*, devemos primeiro recapitular o seguinte exemplo:

```bash
$ echo 'my precious' > rawcontent.txt
$ base64 < rawcontent.txt
bXkgcHJlY2lvdXMK
```

* O programa `echo` redireciona a o **output** para o arquivo `rawcontent.txt`
* O conteúdo do arquivo é enviado como **input** para o comando `base64`

Note o padrão aqui: temos uma *pipeline* de transformação de dados, onde o **output de um programa é utilizado como input** para o próximo programa.&#x20;

Esta técnica de pipeline é utilizada em sistemas UNIX-like com o operador *pipe* `|`.

## UNIX pipelines

Ao invés de escrevemos nossa pipeline em múltiplas linhas, dificultando a legibilidade caso a complexidade aumente, podemos utilizar o operador `|` para montar uma sentença única de comandos encadeados:

```bash
$ echo 'my precious' | base64
bXkgcHJlY2lvdXMK
```

Muito melhor, não? E muito provável você já viu isto em algum lugar, por exemplo:

```bash
$ ps ax | grep ruby
88327 s002  S+     0:00.94 docker run -it ruby irb
88330 s002  S+     0:00.92 /usr/local/bin/com.docker.cli run -it ruby irb
91074 s003  S+     0:00.00 grep ruby
```

O **output** do comando `ps` é enviado como **input** para o comando `grep`. *Cool, uh?* Este pipe é chamado de *pipe anônimo, ou* **anonymous pipe**!

### Anonymous pipe

Este pipe é chamado de **anônimo** justamente por não ter nome e ser temporário, pois o *fd* é criado durante a pipeline e depois é liberado.

Este tipo de **IPC** utiliza uma comunicação tem as seguintes características:

* **One-way**, ou seja, a informação trafega apenas e uma única direção
* **FIFO** (first-in, first-out), ou seja, o output é redirecionado para um pipe e **enfileirado** como input em outro pipe do próximo comando

```bash
$ ps ax | grep docker | tail -n 3

62374 s039  S+     0:05.31 /usr/local/bin/com.docker.cli run -it ubuntu bash
65442 s040  S+     0:02.93 docker run -it ubuntu bash
65445 s040  S+     0:02.86 /usr/local/bin/com.docker.cli run -it ubuntu bash
```

Quando um `|` é criado, abre-se um par de *file descriptors*, uma para escrita e outro para leitura, tal como fizemos na seção anterior com *custom fd*.

Como a pipe é anônima, ambos file descriptors abertos são utilizados apenas no contexto da pipeline e são automaticamente liberados/fechados quando a **pipeline** termina.

Apesar de pipes anônimas `|` serem utilizadas praticamente em quase tudo, é possível criamos pipes **com nomes**?

### Named pipes

Como o próprio nome diz, **named pipes** são pipes *com nomes*. São similares a pipes anônimas; empregam **FIFO** e são uma forma de IPC de via única (**one-way**).

A única diferença é que um named pipe é criado de forma explícita via comando `mkfifo`, onde um arquivo é criado no *filesystem* e aberto para escrita e leitura.

```bash
$ mkfifo myqueue
```

Um arquivo chamado `myqueue` é criado.&#x20;

Vamos enviar uma mensagem para o pipe com o comando `echo`, utilizando redirecionamento de stream `>` que vimos na última seção:

```bash
$ echo 'my precious' > myqueue 
```

Note que o processo fica bloqueado, à espera de algo.

#### IPC one-way

Por ser uma estrutura de fila *FIFO* simples e ser utilizado como *one-way IPC*, o sistema operacional precisa garantir que a mensagem **será recebida por outro processo.** Por isso o processo *escritor*, ou **writer**, fica bloqueado, pois é preciso que outro processo outro processo *leitor* (**reader**) para "consumir" a mensagem do pipe.&#x20;

Em outra sessão do bash, vamos consumir a informação do pipe utilizando o comando `cat`:

```bash
$ cat myqueue
my precious
```

Yay!&#x20;

O mesmo acontece se iniciarmos com o *leitor*: este fica bloqueado à espera que alguma mensagem chegue no pipe, no caso através de outro processo *escritor*.&#x20;

### Implementando um simples Background Job com UNIX pipes

Utilizando **anonymous pipes e named pipes**, podemos explorar a funcionalidade primitiva de um sistema de processamento assíncrono (**background job**).

Começamos por definir os componentes:

1. Um processo *leitor*, ou **consumer**, fica infinitamente à espera de mensagens no *pipe* (fila)
2. Diferentes *escritores*, ou **publishers**, colocam mensagens no pipe de forma assíncrona
3. O processo leitor (**consumer**) recebe cada mensagem no pipe e faz o devido **processamento da mensagem**

:point\_right: Nosso background job irá fazer a simples tarefa de receber uma mensagem **codificada** em *base64*, **decodificá-la**, e então mostrar no screen (STDOUT).

#### **Consumer**

Primeiro, criamos o pipe que representará a "fila" do nosso background job:

```bash
mkfifo myqueue
```

Agora, o consumer fica em **loop infinito** à espera de mensagens na fila.&#x20;

Dentro do *loop*, consome a mensagem, decodifica-a e então mostra no screen:

```bash
while true
do
  ## Fica bloqueado à espera da próxima mensagem na fila
  ENCODED=`cat myqueue` 
  
  ## Quando a mensagem chega na fila, decodifica-a utilizando o comando
  ##  echo e base64 com anonymous pipes
  DECODED=`echo $ENCODED | base64 -d`
  
  echo "Mensagem decodificada: $DECODED"
done
```

E o consumer está pronto. Código final do arquivo `consumer.sh`:

```bash
#!/bin/bash

## Cria o named pipe
mkfifo myqueue

echo 'Aguardando jobs na fila...'

while true
do
  ## Fica bloqueado à espera da próxima mensagem na fila
  ENCODED=`cat myqueue` 
  
  ## Quando a mensagem chega na fila, decodifica-a utilizando o comando
  ##  echo e base64 com anonymous pipes
  DECODED=`echo $ENCODED | base64 -d`
  
  echo "Mensagem decodificada: $DECODED"
done
```

Em uma sessão do bash:

```bash
$ bash consumer.sh
Aguardando jobs na fila...
```

E em outra sessão do bash, podemos utilizar vários *producers* para enviar diversas mensagens codificadas para a fila:

```bash
$ echo 'my precious' | base64 > myqueue
$ echo 'pipes are awesome' | base64 > myqueue
```

Consultando o output na sessão do consumer:

```bash
Mensagem decodificada: my precious
Mensagem decodificada: pipes are awesome
```

### Resumo

Que jornada! Nesta seção vimos a utilização de **UNIX pipes** para IPC, vimos a semelhança e diferença entre anonymous pipes `|` e named pipes, bem como a implementação de um **sistema de background jobs** com pipes.

Agora, é hora de explorar uma forma ainda mais sofisticada de IPC: **UNIX Sockets**.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://web101.leandronsp.com/comunicacao-entre-processos/unix-pipes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
