# File descriptors

File descriptor (ou **fd**) é um arquivo especial que é organizado em uma *file descriptor table* e possui um **identificador único,** que aponta uma referência seja para um dispositivo físico I/O, um arquivo ou até mesmo outro *file descriptor*.

### Standard streams

Todo processo UNIX tem por default 3 *communication channels*, também conhecidos por **standard streams**, que são representados por file descriptors (fd):

* `fd 0`: standard input, ou **STDIN**
* `fd 1`: standard output, ou **STDOUT**
* `fd 2`: standard error, ou **STDERR**

<figure><img src="/files/z7kCxJIJCowZt1MCWgUZ" alt=""><figcaption></figcaption></figure>

#### STDOUT

Vamos analisar o seguinte comando:

```bash
$ echo 'Hello'
Hello
```

* O programa `echo` envia uma mensagem para o **STDOUT**, ou seja, *file descriptor 1*
* STDOUT refere-se ao screen do computador, e por isto a mensagem `Hello` é mostrada na tela

#### STDIN

Agora, vamos a outro exemplo com *STDIN*:

```bash
$ base64
```

Este comando fica à espera de dados em uma *interface interativa* do **STDIN,** que refere-se ao teclado do computador.&#x20;

Então, devemos digitar qualquer texto (neste caso digitei "leandro") e, para finalizar, devemos pressionar a tecla *ENTER\[CR]* seguida de **CTRL+d**, que basicamente finaliza a interface STDIN. Após isto, o comando deve retornar o output:

```bash
bGVhbmRybwo=
```

* O programa `base64` fica à espera do **STDIN**, ou seja, *file descriptor 0*
* STDIN refere-se ao teclado do computador, e por isto abre-se uma *interface interativa* para receber informação a partir do teclado
* Digitei "leandro", pressionei **ENTER** e em seguida **CTRL+d** para sair da interface STDIN
* O programa capturou a informação através do *STDIN* e converteu a informação para um formato *base 64*
* O programa enviou a informação convertida em base 64 para o *STDOUT*
* STDOUT refere-se ao screen do computador, e por isto o conteúdo base 64 é mostrado na tela

Interessante notar que programas tais como o `base64` interagem tanto com o stream STDIN quanto o STDOUT.

#### STDERR

E se passarmos um argumento, por exemplo o nome de um arquivo inexistente para o comando `base64`?

```bash
$ base64 name.txt
Unable to open 'name.txt': No such file or directory
```

Como o programa fica à espera de informação a partir do STDIN, é lançado um erro caso o STDIN não proveja a informação.&#x20;

Todo programa, por padrão, envia seus erros para a stream **STDERR**, representada pelo *file descriptor 2*.&#x20;

E qual o dispositivo de saída do ***STDERR***? É o mesmo do *STDOUT*, e justamente por este motivo conseguimos ver a mensagem de erro na tela!

### Redirecionamento de streams

Recapitulando, sabemos que *file descriptors (fd)* são arquivos especiais do *filesystem*, mas para todo efeito, são **arquivos**.&#x20;

E, uma vez que standard streams são file descriptors, será possível *redirecionarmos*, ou seja, **mudarmos o destino** de um stream para outro stream ou até mesmo qualquer outro arquivo do *filesystem*?&#x20;

Sim, é possível, com o uso dos operadores `>` e `<`, utilizando o número do *fd* como prefixo.

* Redirecionamento de **STDIN**: `<`, ou `0<`
* Redirecionamento de **STDOUT**: `>`, ou `1>`
* Redirecionamento de **STDERR**: `2>`

Voltando ao exemplo do comando `echo`, podemos redirecionar o STDOUT para outro arquivo, e desta forma, o output será enviado para o arquivo de redirecionamento:

```bash
$ echo leandro 1> name.txt
```

Note que o output não foi mostrado, pois foi redirecionado para o arquivo `name.txt`. Se executarmos o comando `cat name.txt`, podemos ver o resultado no screen!

Voltando ao exemplo do base64, que tal redirecionarmos o STDIN default (dispositivo de teclas) para que seja a partir do arquivo contendo o nome?

```bash
$ base64 0< name.txt
bGVhbmRybwo=
```

Nice!&#x20;

Um "açúcar sintático" no bash é que, quando quisermos redirecionar o *STDIN* ou *STDOUT*, **não precisamos colocar o sufixo** do *file descriptor*:

```bash
$ echo leandro > name.txt # default do > é 1
$ base64 < name.txt       # default do < é 0
bGVhbmRybwo=
```

E se tentarmos com um arquivo não-existente?

```bash
$ base64 blah.txt
Unable to open 'blah.txt': No such file or directory
```

Muito similar ao erro que tivemos anteriormente. Como o arquivo **não é encontrado**, é lançado um erro, que vai para o *STDERR*, que por sua vez é mostrado por *default* no screen.

Mas podemos redirecionar o **STDERR** também para um outro arquivo, tal como o *STDOUT e STDIN*?&#x20;

Sim, mas no caso do STDERR, precisamos utilizar o sufixo do file

```bash
$ base64 blah.txt 2> err.txt
```

Confirmando que o conteúdo foi redirecionado para `err.txt`:

```bash
# Como o cat é um comando que também fica à espera de STDIN, 
#  também funciona se utilizarmos redirecionamento de STDIN
#  Exemplos:
#    cat 0< err.txt
#    cat < err.txt
# Ou, simplesmente:
$ cat err.txt
Unable to open 'blah.txt': No such file or directory
```

Podemos também concentrar tanto output quanto erros num único arquivo:

```bash
$ echo 'My message' > out.log 2>&1
```

O `&1` significa o stream atual para o file descriptor 1, neste caso o arquivo `out.log`.&#x20;

### Utilizando outros file descriptors

Com exceção dos *fd* padrão 0, 1, e 2, podemos criar outros file descriptors e utilizarmos como IPC? Sim, podemos! Vamos começar criando um diretório onde vamos armazenar estes fd temporários:

```bash
$ mkdir /tmp/fd
```

Vamos supor que queremos atribuir o `fd 42`. Devemos então preparar nosso fd, que será um canal de *comunicação de única via,* ou **single-communication channel** entre dois processos.&#x20;

Primeiro, abrimos o **fd** para para escrita `>` (STDOUT):

```bash
$ exec 42> /tmp/fd/42
```

Agora, redirecionamos uma mensagem para o *fd* utilizando **redirecionamento de stream** de escrit&#x61;**:**

```bash
$ echo 'Some message' >&42
```

Então com o comando **base64**, e sabendo que podemos ler de qualquer fd com redirecionamento de streams, fazemos o redirecionamento de *leitura:*

```bash
# Primeiro, abrir o fd para leitura < (STDIN)
$ exec 42< /tmp/fd/42 

# Executar o comando com o redirecionamento para o fd
$ base64 <&42
U29tZSBtZXNzYWdlCg==
```

File descriptors são recursos, portanto depois de utilizados, devem ser "liberados" no sistema operacional, ou seja, **fechados tanto para escrita quanto leitura**:

```bash
$ exec 42<&-
$ exec 42>&-
```

### Resumo

Nesta seção, vimos como diferentes processos se comunicam utilizando uma forma primitiva de IPC, que são os *file descriptors*.

Uma vez que entendemos isto, já podemos ir para a próxima etapa que irá explorar outra forma de comunicação um pouco mais sofisticada, **UNIX pipes**.


---

# 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/file-descriptors.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.
