Fluxos E/S stdout, stdin e stderr
Um assunto bem interessante no mundo do terminal são os fluxos de E/S (entrada/saída). Veja o comando abaixo.
$ echo Hello World > arq.txtO que aconteceu? Bem, verifique o diretório onde você executou esse comando e você deverá um arquivo chamado arq.txt, olhe dentro desse arquivo e deverá ver o texto Hello World. Muitas coisas aconteceram em um comando, então vamos detalhar.
A primeira parte desse comando é:
$ echo Hello WorldSabemos que o comando echo imprime Hello World na tela, mas como? Os processos usam fluxos de E/S para receber entrada e retornar saída. Por padrão, o comando echo pega a entrada (entrada padrão ou stdin) do teclado e retorna a saída (saída padrão ou stdout) para a tela. É por isso que quando você digita echo Hello World em seu shell, você obtém Hello World na tela. No entanto, o redirecionamento de E/S nos permite alterar esse comportamento padrão, proporcionando maior flexibilidade de arquivos.
Vamos prosseguir para a próxima parte do comando:
>O > é um operador de redirecionamento que nos permite alterar para onde vai a saída padrão (stdout). Ele nos permite enviar a saída de echo Hello World para um arquivo em vez de para a tela. Se o arquivo ainda não existir, ele será criado para nós. No entanto, se existir, ele será sobrescrito. E é basicamente assim que funciona o redirecionamento stdout!
Bem, digamos que eu não queira sobrescrever meu arq.txt, felizmente também existe um operador de redirecionamento para isso, >> ou seja você fará um append no arquivo.
$ echo Hello World >> saida.txtOk vimos que temos o stdout que podemos usar, como um arquivo ou a tela como forma de saída. Bem, também existem diferentes fluxos de entrada padrão (stdin) que podemos usar. Sabemos que temos stdin de dispositivos como o teclado, mas podemos usar arquivos, saída de outros processos e do terminal também, vamos ver um exemplo.
Vamos usar o arquivo arq.txt neste exemplo, lembre-se de que ele continha o texto Hello World.
$ cat < arq.txtExecutando o comando vemos que o arq.txt é colocado no stdin do comando cat, e o conteúdo do arquivo é mostrado na tela.
Podemos agora enviar o stdout do comando cat para um arquivo.
$ cat < arq.txt > saida.txtVamos tentar algo um pouco diferente agora, vamos tentar listar o conteúdo de um diretório que não existe no seu sistema e redirecionar a saída para o arquivo arq.txt novamente.
$ ls /tmp/naoexiste > arq.txtOk, mas reparou que foi exibido na tela:
ls: não foi possível acessar '/tmp/naoexiste': Arquivo ou diretório inexistenteAgora você provavelmente está pensando: aquela mensagem não deveria ter sido enviada para o arquivo? Na verdade, há outro fluxo de E/S em jogo aqui chamado erro padrão (stderr). Por padrão, o stderr também envia sua saída para a tela, mas é um fluxo completamente diferente do stdout.
Então você precisará redirecionar sua saída de uma maneira diferente. Teremos que usar descritores de arquivo. Um descritor de arquivo é um número não negativo usado para acessar um arquivo ou fluxo. Iremos aprofundar isso mais tarde, mas por enquanto sabemos que o descritor de arquivo para stdin, stdout e stderr é 0, 1 e 2 respectivamente. Então agora, se quisermos redirecionar nosso stderr para o arquivo, podemos fazer isso:
$ ls /tmp/naoexiste 2> arq.txtAgora, e se eu quisesse ver stderr e stdout no arquivo arq.txt? Também é possível fazer isso com descritores de arquivo:
$ ls /tmp/naoexiste > arq.txt 2>&1Isso envia os resultados de ls /tmp/naoexiste para o arquivo arq.txt e então redireciona o stderr para o stdout via 2>&1. A ordem das operações aqui é importante, 2>&1 envia stderr para qualquer que seja o stdout que esteja apontando. Nesse caso, stdout está apontando para um arquivo, então 2>&1 também envia stderr para um arquivo. Portanto, se você abrir o arquivo arq.txt, verá stderr e stdout. No nosso caso, o comando acima gera apenas stderr.
Existe uma maneira mais curta de redirecionar stdout e stderr para um arquivo, e você verá ele bastante por aí:
$ ls /tmp/naoexiste &> arq.txtAgora, e se eu não quiser nada desse lixo e quiser se livrar completamente das mensagens stderr? Bem, você também pode redirecionar a saída para uma chamada de arquivo especial /dev/null e ela descartará qualquer entrada.
$ ls /tmp/naoexiste 2> /dev/null