⌨️Redirecionando inputs e outputs

Nesse capítulo estudaremos a redireção de inputs e outputs no Linux e o que file descriptors têm a ver com esse assunto.

File descriptors

File descriptors podem ser entendidos como números inteiros não negativos que representam um arquivo aberto em um processo. Qualquer arquivo aberto em um processo, seja para leitura ou escrita, receberá um file descriptor e quaisquer operações subsequentes serão realizadas a partir desse número de identificação.

Lembra do princípio de que tudo é arquivo no Linux? Esse conceito é bem explorado nessa parte, pois esse arquivo pode ser qualquer coisa: um arquivo comum, um socket ou um dispositivo.

Todo processo tem três file descriptors abertos por padrão:

File Descriptor
Propósito/dispositivo

0

Entrada padrão (/dev/stdin)

1

Saída padrão (/dev/stdout)

2

Saída de erro (/dev/stderr)

  • A entrada padrão (stdin) refere-se ao dispositivo padrão para entrada de dados no computador, como o teclado. Ler do file descriptor 0 em um processo, no geral, significa ler dados do teclado.

  • A saída padrão (stdout) refere-se o dispositivo padrão para a saída dos dados dos comandos. Geralmente é a tela.

  • A saída de erro (stdout) será levada para o dispositivo padrão para saída dos erros dos comandos - permitindo montar um log dos erros de forma simples. Geralmente é atrelada a mesma saída que o stdout, a tela.

Vamos agora entender os redirecionamentos do bash:

Redirecionando a saída padrão

É possível redirecionar a saída padrão usando os seguintes símbolos:

  • >: redireciona a saída padrão para uma localização, sobrescrevendo os dados da localização.

  • >>: redireciona a saída padrão para uma localização, adicionando o conteúdo ao fim do arquivo.

Também é possível utilizar as notações 1> e 1>> para especificar que o redirecionamento é do stdout. Porém, caso não seja especificado o número do file descriptor, por padrão o bash irá redirecionar o stdout.

Utilizar qualquer um desses redirecionamentos apontando para um nome de arquivo irá fazer com que esse arquivo seja criado, caso não exista. Isso é feito antes da fase de executar o comando - ou seja, mesmo que o comando que usa o redirecionamento resulte em erro, o bash ainda irá criar o arquivo.

Alguns exemplos de uso:

  • Criando e escrevendo conteúdo em um arquivo:

  • Redirecionando o resultado do comando ls para o arquivo resultado.txt:

  • Adicionando duas vezes o conteúdo do comando ls / para o arquivo resultado-duplo.txt:

Trabalhando com pipes

Pipes são canais de comunicação unilateral entre processos, que permitem conectar a saída padrão de um comando para a entrada padrão de outro. Há dois tipos de pipes: anonymous pipes (ou unamed pipes) e FIFOs (First In, First Out ou named pipes). Nessa seção, veremos o tipo de pipe mais simples, o unamed pipe.

O uso é bem simples: comando1 | comando2. Nessa linha, a saída padrão (stdout) do comando1 será passada para a entrada padrão (stdin) do comando2, como no exemplo abaixo, para contar a quantidade de linhas de um arquivo lido pelo cat.

É possível utilizar vários pipes encadeando vários comandos, e isso revela o quão poderosa é a linguagem do shell.

tee

O utilitário tee permite salvar uma saída para um arquivo e para o stdout. Tudo o que o usuário tem que fazer é realizar um pipe do comando para o comando tee nomedoarquivo, como ls | tee diretorio_atual.txt.

Note que o comando tee não irá sobrescrever o arquivo, caso ele exista, apenas adicionará o conteúdo ao fim dele.

Para testar o comando cowsay, instale-o com sudo apt install cowsay -y

Redirecionando a saída de erro

A saída de erro (stderr) é a principal para realizar debugging de comandos que não foram executados com sucesso. Por padrão, ela irá para a tela.

Podemos diferenciar a saída padrão da saída de erro ao tentar redirecionar o stdout para um arquivo. Na tela será apresentado o conteúdo do stderr, enquanto que o stdout irá para o arquivo.

Por exemplo, ao tentar listar um diretório não existente, o que é impresso na tela é o resultado do stderr. Redirecionar o resultado para > resultará em um arquivo vazio, pois não houve saída padrão, apenas de erros.

O redirecionamento da saída de erro é bem semelhante ao da saída padrão:

  • 2>: redireciona a saída de erro para uma localização, sobrescrevendo os dados da localização.

  • 2>>: redireciona a saída de erro para uma localização, adicionando o conteúdo ao fim do arquivo.

Nesse caso, o 2 antes de > ou >> é obrigatório, para se diferenciar do file descriptor do stdout. Abaixo está um exemplo do redirecionamento.

Redirecionando as saídas para o mesmo lugar

Vamos executar o seguinte comando: ls / naoexistente. Esse comando irá concatenar o stderr e o stdout na tela, conforme imagem abaixo.

É possível realizar dois redirecionamentos na mesma linha, como ls / naoexistente > resultados.txt 2> erros.txt. Nesse caso, o arquivo resultados.txt irá armazenar o stdout e erros.txt guardará os erros.

Entretanto, caso queiramos armazenar o stderr e o stdout no mesmo arquivo, tal notação não terá o resultado desejado:

Para essa tarefa, devemos utilizar a notação &numerodofiledescriptor. O shell irá interpretar isso como "a mesma saída do file descriptor numerodofiledescriptor".

No exemplo abaixo, primeiramente redirecionamos o stdout para o arquivo concatenado.txt e após isso, realizamos o redirecionamento do stderr (2>) para "a mesma saída do file descriptor 1 (stdout)". Dessa forma, as duas saídas irão para o mesmo arquivo.

Redirecionando a entrada padrão

Para redirecionar a entrada padrão (stdin), utilize o símbolo <, passando após ele o nome de um arquivo. Esse arquivo será lido como entrada padrão, substituindo o uso de teclado e permitindo a execução não interativa de scripts que esperam interação via teclado.

A exemplo no LInux, temos o comando cowsay (para instalar: sudo apt install cowsay -y), que imprime uma frase digitada pelo teclado em uma ASCII art. Para redirecionar algo que queremos que a vaquinha fale, é só criar um arquivo e redirecionar o stdin para o comando cowsay.

O vazio - /dev/null

No Linux existe um arquivo de dispositivo especial em que qualquer redirecionamento para ele é descartado - um buraco negro do Linux - o /dev/null.

Há vários usos dele, mas um dos mais usuais é o de suprimir a saída de erros. Modificando o exemplo anterior do ls / naoexistente, obtemos a seguinte linha: ls / naoexistente 2>/dev/null:

Last updated