Linux – Estudando e explorando o 2>&1

Uma recurso muito utilizado em scripts Linux para Desktop, Servidores e até em Sistemas Embarcados com Linux, porém muitos não sabem o significado ou o correto uso destas opções, e irei abordar em detalhes neste artigo.

É muito comum em ambiente Linux encontrarmos o uso das seguintes expressões:

Quer ver um exemplo execute o comando abaixo:

E você verá quantos scripts em seu /etc/init.d possuem o uso do 2>&1.

Vamos primeiramente entender o que são os números da expressão 2>&1.

File Descriptor Nome Ação
0 stdin Entrada padrão do sistema
1 stdout Saída padrão do sistema
2 stderr Saída de erro padrão do sistema

Então acabamos de descobrir que os números 0, 1 e 2 são file descriptors(fd) que o Linux utilizada para stream dos scripts e aplicações, comportando-se normalmente como a Figura01.

linuxIO_cleitonbueno.com
Figura01 – File Descriptors Stream IO no Linux

Agora os operadores > e &:

Operador Ação
> Redireciona
&  Indica que o numero é um fd

Então o ‘>‘ redireciona e o ‘&‘? Esse a função dele aqui é bem especial, neste caso ele que diz a aplicação que 1, ou o numero depois dele, é um file descriptor e não um arquivo, caso você omita o operador ‘&‘ ele irá criar um arquivo com o nome 1.

Então podemos chegar a conclusão sobre o 2>&1 como a Figura02.

LinuxRedirectIO_cleitonbueno.com
Figura02 – Detalhes sobre 2>&1

Vamos a um exemplo pratico e simples vendo o uso dos 3 files descriptors(input, output e err), exemploIO_1.sh:

Execute a aplicação mas não digite o nome ainda.

Neste momento vamos pegar o PID(Process Identification) do nosso script e verificar os file descriptors dele, vamos usar o comando pgrep ou caso prefira pode usar o ps.

Acima obtemos varias informações, primeiro com o pgrep e o nome do script pegamos o PID do processo, depois com o ls listamos no /proc/15655/fd/ os files descriptors do processo, onde 0,1 e 2 apontando para /dev/pts/3 e ao digitar o comando w podemos ver que o pts3 é o pseudo-terminal onde estou executando o nosso script exemploIO_1.sh.

Então, a saída padrão, entrada padrão e saída de erro estão todos para o terminal onde esta executando o script, vamos voltar ao nosso script e agora entrar com o nome.

Agora adaptando o que aconteceu ao script e associando com a Figura01, temos como resultado a Figura03.

linuxIO_proc_fd_cleitonbueno.com
Figura03 – Associando input, output e error ao script

 

 

Manipulando o file descriptor

Usando o mesmo script anterior, vamos executar ele mas de uma forma que não queremos ver o erro, então iremos manipular o fd 2(stderr).

Executando o script e novamente não entrando com o nome:

Vamos ver o que mudou no processo do script agora.

Agora o file descriptor (2) stderr mudou e no lugar de apontar para o terminal esta para o /dev/null, então não devemos mais ver o erro na tela, vamos conferir.

Então se eu quiser que stderr e stdout não mostrem nada, eu uso o famoso 2>&1 ou &> da seguinte maneira:

Ambos os modos irei obter o mesmo resultando, stdout e stderr para /dev/null.

As vezes podemos ver scripts assim:

Que para o processo será:

A explicação é que stdout(2) esta redirecionando para o stderr(1) mas este por si esta enviando para /dev/null, o correto é então especificar para onde enviar e em seguida apontar os dois file descriptors.

Do mesmo modo que envio para /dev/null posso enviar para um arquivo, então vamos enviar o stderr para /dev/null e stdout para /tmp/saida.log.

Analisando o PID do processo:

O incomodo aqui é que todo output da aplicação ficou no /tmp/saida.log:

O que podemos fazer neste caso é deixar apenas o stderr do script enviando para /dev/null e dentro do script direcionamos o echo para /tmp/saida.log, segue o exemploIO_2.sh:

Executando o exemploIO_2.sh:

Verificando o processo:

O processo do script direcionara o stderr para outro local e dentro do script em dois lugares direcionamos o stdout(1) para o arquivo /tmp/saida.log.

Da mesma maneira podemos manipular o file descriptor stdin(0), vamos ao exemploIO_3.sh:

Deve-se criar o arquivo /tmp/nome.txt e dentro insira qualquer nome, execute o script da seguinte maneira:

Coloquei um atraso de 30s para dar tempo de ver o processo, então verificando o fd do processo:

O script irá usar o arquivo passado no 0< como entrada e é o que pode-se ver na saída acima.

Para finalizar um exemplo de como criar um file descriptor dentro da aplicação e utiliza-lo, vamos ao exemploIO_4.sh:

Executando e listando o fd do processo:

Criamos um file descriptor (28) para /tmp/exemploIO_4.sh.log que irá registrar quando iniciar nosso script e quando estiver saindo. Do mesmo modo que podemos criar um fd(file descriptor) também podemos fechá-lo.

Utilizando o script anterior fecharemos stderr e criando fd(28) apenas para gravar quando a aplicação começar e em seguida após digitar o nome irá fechar o fd(28), o exemploIO_5.sh ficara como abaixo:

Como pode-se ver para fechar um file descriptor colocamos o numero do fd>&-, como foi feito com stderr(2) no inicio do script e com o fd(28) na linha 20, para stdint seria fd<&-.

Executando o script exemploIO_5.sh, mas não digitando o nome:

Verificando o processo do exemploIO_5.sh:

Podemos notar que o fd(2) do stderr não existe, então não é para aparecer nenhum erro no terminal e o fd(28) para /tmp/exemploIO_5.sh.log esta criado, após digitar o nome ele deverá ser fechado e irá ter armazenado o timestamp da hora que iniciou o script, vamos inserir o nome e em seguida listar o diretório fd do processo novamente.

Listando novamente o diretório fd do processo:

Durante os 30s de delay que inseri apos digitar o nome podemos listar o processo e agora o fd(28) não existe mais, vamos ver se o conteúdo foi inserido no /tmp/exemploIO_5.sh.log:

Então tudo saiu como planejado, registrou o timestamp no fd(28) e como fechamos o stderr(2) o erro do cd não foi reportado.

E assim o uso de file descriptors e a manipulação de stdin, stdout e stderr pode-se estender dentro do script como fora, o fd(28) que criamos pode ser passado ao executar o script como fizemos com 2> e 1>, e tem-se um enorme leque de combinações e opções para manipular estes fd e streams IO no Linux.

Até a próxima!

Share Button

CC BY-NC-SA 4.0 Linux – Estudando e explorando o 2>&1 by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

  • Cleiton! Muito bom! Esses dias mesmo eu estava pesquisando sobre isso. Sempre tive essa dúvida e curiosidade!
    Abraços!

    • Opa, que bom que gostou Fernando. A dias estou para escrever sobre isso, e partiu depois de ver em scripts e na duvida de alguns que usam.

      Abraço.

  • Emanuel Raul

    Show bola….