julho 29, 2019

Descritores de Arquivos (STDIN, STDOUT e STDERR)

Essa é uma daquelas coisas que a gente usa o tempo todo no console, no terminal ou nos scripts em shell, mas não faz a mínima ideia do que se trata, de como funciona, e ainda enfrenta uma enorme dificuldade de encontrar qualquer coisa a respeito que não seja incompreensível ou enigmática.

Escrever, especialmente para introduzir certos conceitos mais complexos de forma simples, pode ser uma tarefa bem ingrata e arriscada. Se, por um lado, eu corro o risco de ainda estar sendo complexo demais para quem está começando, por outro, é bem provável que, no processo de redução, eu acabe cometendo heresias facilmente encontradas pelos especialistas no assunto.

Por isso mesmo, eu recomendo que este artigo seja encarado apenas como uma porta de entrada (STDIN) para o assunto. Se você procurar, vai encontrar muito material bom e mais completo na internet (STDOUT) e, aos especialistas, não se acanhem em apontar as minhas falhas (STDERR).

O que é um descritor de arquivos?

Um descritor de arquivos ou, como é chamado em inglês, file descriptor (FD), é basicamente um número que identifica de forma única um arquivo aberto no sistema e uma descrição dos recursos de dados que ele aloca e como ele pode ser acessado.

Quando um processo pede para o sistema abrir um arquivo, o kernel devolve um descritor de arquivo que, por sua vez, aponta para uma entrada numa tabela global de descrição de arquivos (GDT), onde registra informações como a localização do arquivo, a quem ele pertence, quais as suas permissões e restrições de acesso, entre outros detalhes.

Intrinsecamente, não é um conceito simples. Mas, a menos que você seja um engenheiro de software, tudo que nós precisamos saber sobre eles para trabalhar com o shell do Linux e começar a programar, é que os três primeiros descritores de arquivos no Linux/Unix são, por padrão...

0 - A entrada padrão - STDIN (standard input)
1 - A saída padrão   - STDOUT (standard output)
2 - A saída de erro  - STDERR (strandard error)

Além de seus números, esses descritores de arquivos podem ser representados conforme suas direções de acesso:

STDIN  - 0<
STDOUT - 1>
STDERR - 2>

STDIN - a entrada padrão

Quando você está no terminal e digita alguma coisa no seu teclado, essa cadeia de dados (stream) vai para a STDIN, que é a forma mais básica de interface pela qual o usuário pode enviar informações para os programas.

STDOUT - a saída padrão

Da mesma forma que as informações entram no sistema pela STDIN, é pela STDOUT, que pode ser representada pelo monitor ou, mais exatamente, pelo console ou terminal, que o dispositivo padrão de saída faz uma interface com o usuário.

STDERR - a saída padrão de erro

Considerando que as mensagens enviadas por um programa podem ser tanto o resultado esperado do processamento quanto a indicação de que algo deu errado, faz todo sentido haver um descritor de arquivos para lidar exclusivamente com as saídas de erro, e é aí que entra a saída padrão de erros, ou STDERR.

Operadores de redirecionamento

As entradas e saídas podem ser manipuladas através de alguns operadores básicos de redirecionamento que orientam as cadeias de dados de um local para outro.

 |   (pipe) ................ "canaliza" a STDOUT de um programa para a STDIN de outro.
 >   (saída) ............... redireciona a STDOUT para um arquivo.
 >>  (append de saída) ..... anexa a STDOUT ao final de um arquivo.
 <   (entrada) ............. redireciona uma cadeia de dados para a entrada.
 <<  (append de entrada) ... anexa uma cadeia de dados à entrada
 <<< (here string) ......... expande um valor e envia para a STDIN de um comando.

Observação: o termo "arquivo" aqui deve ser entendido como o destino de uma cadeia de dados que, de certa forma, é sempre um arquivo, mas nem sempre é o tipo de arquivo com que estamos acostumados a lidar nas pastas do nosso disco.

Operadores de redirecionamento avançados

Quando queremos manipular as entradas e saídas de formas um pouco mais específicas, às vezes apenas por uma questão de compatibilidade, nós podemos utilizar operadores muito semelhantes aos que já vimos, mas que, em alguns casos, podem ter comportamentos ligeiramente diferentes.

 1>  .... tem o mesmo comportamento do operador de saída (>)
 1>> .... tem o mesmo comportamento do append de saída (>>)
 2>  .... redireciona para a saída de erro (STDERR)
 2>> .... anexa cadeia de dados à STDERR
 -   .... redireciona o que vier da STDIN
 &>  .... redirecionamento para STDOUT e STDERR
 >&  .... redirecionamento entre descritores de arquivos, e não arquivos

Conclusão

Até para dar um tempo para você assimilar todos esses conceitos e operadores, nós não vamos abordar os aspectos práticos neste artigo, mas não vamos parar por aqui. Eu pretendo criar uma postagem e um vídeo em breve cobrindo um pouco mais sobre o assunto e apresentando muitos exemplos. Contudo, espero ter ajudado a deixar esse conceito um pouco mais claro e, com isso, contribuído para que os seus próximos scripts sejam feitos de forma um pouco mais consciente.

Dúvidas? Correções? Outras ideias?

A seção de comentários é sua!

 

Nenhum comentário:

Postar um comentário

O sistema de comentários do Blogspot é um lixo e praticamente me obriga a liberar ou moderar todos os comentários. Portanto, eu peço perdão antecipadamente caso o seu comentário demore para aparecer.

Mas não se acanhe por causa disso! :-)