Condutores no Linux (stdin e stdout) [Guia Básico]

Outro conceito importante é o redirecionamento. Como o Linux foi criado por programadores para programadores, fez-se necessário que os comandos e processos tivessem a habilidade de tratar as entradas e saídas de dados com grande facilidade. Os Condutores no Linux são a forma como os programas conversam entre si através das entradas e saídas de dados.

Antes de detalharmos a habilidade de redirecionamento do Linux precisamos definir o que são entradas padrão, saída padrão e saída de erro:

  • Entrada Padrão (stdin) é a entrada de um fluxo de texto. Como exemplos temos o teclado, o mouse, um disquete, etc. Todos eles alimentam o computador com informações. Pode ser representado pelo número 0.
  • Saída Padrão (stdout) é a saída de um fluxo de texto em condições normais. Como exemplos temos o monitor, a impressora, o disquete, um arquivo, etc. Todos eles recebem informações do computador. Pode ser representado pelo número 1.
  • Saída de Erro (stderr) é a saída de um fluxo de texto em condições de erro ou insucesso em um determinado processamento. A saída de erro poderá ser direcionada para o monitor ou para um arquivo de LOG. Pode ser representado pelo número 2.

Você pode ver esses fluxos de dados no diretório /dev com o comando:

$ ls -l /dev/std*
lrwxrwxrwx 1 root root 15 ago 15 10:53 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 ago 15 10:53 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 ago 15 10:53 /dev/stdout -> /proc/self/fd/1

Como você pode perceber, o arquivo /dev/stderr é um link simbólico para um arquivo no /proc/self/fd/2. O arquivo /dev/stdin aponta para o /proc/self/fd/0 e /dev/stdout para /proc/self/fd/1.

O diretório /proc/self é uma representação do Kernel para dar informações sobre o processo em execução. Neste pseudo-diretório especial é possível acessar várias informações sobre o processo que está sendo executado no momento. O diretório /proc/self/fd é também uma abstração que contém os descritores de arquivos (file descriptors), que é outra abstração que o Linux e o Unix fazem para representar através de um arquivo um recurso de entrada ou saída de dados. É a forma que os programadores encontraram de dar acesso fácil para entrada e saída de dados.

É por isso que o stderr é representado pelo número 2, o stdin pelo número 0 e o stdout pelo 1.

É por causa dos descritores de arquivos que podemos redirecionar a entrada padrão ou a saída padrão do fluxo de dados de um determinado processo para outro processo ou um arquivo com muita facilidade.

Para redirecionar um resultado de uma saída para uma entrada de dados ou arquivo utilizamos o sinal de maior “>“.

E para direcionarmos algum arquivo como uma entrada de dados usamos o sinal de menor “<“. 

O sinal duplo “>>” significa adicionar algo, geralmente ao final de um arquivo, sem sobrescrever o seu conteúdo. 

E o sinal duplo <<palavra geralmente serve para permitir que o usuário entre com dados digitando no terminal, até que a palavra indicada seja digitada, uma vez que a palavra funciona como um delimitador.

O sinal “&” pode ser usado para juntar as saídas como em 2>&1.

Ainda podemos redirecionar uma saída para uma entrada usando uma barra vertical especial, o sinal em inglês chamado “pipe” “|” ou duto. 

E os processos podem estar ligados aos terminais, conhecidos como tty. O termo tty deriva da palavra Teletype. 

Nos primórdios do Linux, o administrador utilizava o terminal principal do computador, que era representado pelo arquivo /dev/console e os usuários eram ligados aos terminais “burros” através de placas e conexões seriais, representados pelos arquivos /dev/ttySN, onde N era o número do terminal ao qual o usuário estaria ligado.

Assim, terminais no Linux são representados pelos descritores de arquivos no diretório /dev/ com prefixo tty:

$ ls -1 /dev/tty*
/dev/tty
/dev/tty0
/dev/tty1
( ... )

O Linux mantém os terminais, mas de forma virtual, que podem ser acessados com a combinação de teclas Ctrl-Alt-F1, Ctrl-Alt-F2 até Ctrl-Alt-F6, tanto em ambiente gráfico como em ambiente texto.

O comando “ps -a” pode mostrar quais processos estão conectados a quais terminais:

$ ps -a
  PID TTY          TIME CMD
 2738 tty2     00:12:41 Xorg
 2751 tty2     00:00:00 gnome-session-b
 9274 pts/0    00:00:00 ps

Observe que o ambiente gráfico está atrelado ao terminal tty2.

No exemplo o comando “ps” não está atrelado a um tty, mas ao pts.

O termo pts vem de Pseudo-Terminal, que nada mais é do que um terminal tty emulado por um programa, como, por exemplo, o ssh. Então os programas em execução através de uma conexão remota, estarão atrelados a um terminal falso denominado pts.

Existe também o comando tty, devolve qual é o terminal que o processo do shell está atrelado, seja ele um terminal real (tty) ou emulado (pts):

$ tty 
/dev/pts/0

Usando essa premissa, é simples manipular dispositivos no Linux através dos descritores de arquivos no diretório /dev/.

Por exemplo, é possível mandar uma mensagem para um usuário remoto conectado via ssh num terminal. Para isto, basta saber qual é o terminal que ele está conectado com o comando w:

$  w
 23:40:41 up 1 day, 17:57,  2 users,  load average: 0.00, 0.02, 0.02
USER     TTY      FROM             [email protected]   IDLE   JCPU   PCPU WHAT
arthur   pts/0    10.211.55.2      10:31    1:52   0.28s  0.28s -bash
uiraribe pts/1    10.211.55.2      23:36    1.00s  0.03s  0.00s w

Desta forma, pode-se mandar uma mensagem para o Arthur no pts/0, utilizando o comando echo seguido do redirecionador “>” e o descritor de arquivos que representa o pseudo-terminal pts/0:

$ echo "Hello" > /dev/pts/0

Qualquer comando pode ter a sua saída redirecionada para um arquivo, ou para um dispositivo utilizando um descritor de arquivos que o representa.

No exemplo seguinte listamos os arquivos num diretório gravando o resultado no arquivo saída.txt :

$ ls > saida.txt 

O redirecionamento é utilizando principalmente por programas ou quando o resultado de um processamento não será observado diretamente pelo usuário no terminal, mas enviado para outro programa, para um arquivo ou para um dispositivo. 

Aqui o programa mail recebe como argumento o endereço de e-mail e ao invés de utilizarmos o teclado como entrada padrão, redireciona-se o arquivo texto e-mail.txt para o programa mail na entrada padrão dele com o sinal “<“:

$ mail [email protected] < e-mail.txt

Para enviar toda a saída do programa folha_pagamento para o arquivo1, inclusive com os erros:

$ ./folha_pagamento > arquivo1

É possível filtrar somente a saída padrão do programa folha_pagamento para arquivo1, SEM os erros, usando somente o descritor “1”:

$ ./folha_pagamento 1 > arquivo1

Se quisermos enviar toda a saída de erros para o arquivo arquivo_ erro.log, podemos usar o descritor “2”:

./folha_pagamento 2 > arquivo_erro.log

Tanto a saída padrão e os erros podem ser enviados de forma combinada para o arquivo arquivo1, usando “2>&1” ou “1>&2” (não faz diferença a ordem) :

$ ./folha_pagamento > arquivo1 2>&1

É possível também separar as saídas em arquivos diferentes, enviando o resultado com a saída normal para o arquivo_sucesso.log e a saída de erro para o arquivo_erro.log.

$ ./folha_pagamento 1 > arquivo_sucesso.log 2> arquivo_erro.log

Outra possibilidade é enviar somente a saída de erros para o limbo usando a abstração de /dev/null:

$ ./folha_pagamento 2 > /dev/null

O mesmo pode ser feito para enviar os erros para a impressora, usando a abstração que representa impressoras no /dev/lp0:

$ ./folha_pagamento 2 > /dev/lp0

Toda vez que você quer enviar a saída padrão de um programa para a entrada padrão de outro programa, você precisa usar um condutor, com o sinal “|” do teclado.

Neste exemplo, o resultado do programa folha_pagamento é enviado como entrada para o programa imprime_boletos e a saída de erro do imprime_boletos para o arquivo erro.log:

$ ./folha_pagamento | imprime_boletos 2> erros.log

Para mandar um email do terminal com o conteúdo de um arquivo, pode-se usar o redirecionador “<“:

$ mail [email protected] -s urgent < mail.txt

Para receber dados do terminal e enviá-los para a entrada padrão de um comando, pode-se usar o “<<palavra”. Desta forma o terminal irá receber um texto do teclado, até que a palavra “fim” for digitada em uma linha:

$ mail [email protected] -s urgent <<fim
> Olá,
> Este é um email de teste
> fim

É comum o Linux redirecionar a saída de erros para o descritor de arquivos especial /dev/null. Este arquivo especial é o limbo do Linux, onde tudo que vai para lá some:

$ find / -name arquivo 2>/dev/null

Desta forma, os erros que o find encontrar não serão mostrados no terminal, somente a saída padrão.

Aprenda muito mais sobre Linux em nosso curso online. Você pode efetuar a matrícula aqui. Se você já tem uma conta, ou quer criar uma, basta entrar ou criar seu usuário aqui.

Gostou? Compartilhe