File descriptors
File descriptor (ou fd) é um arquivo especial que é organizado em uma file descriptor table e possui um identificador único, que aponta uma referência seja para um dispositivo físico I/O, um arquivo ou até mesmo outro file descriptor.
Standard streams
Todo processo UNIX tem por default 3 communication channels, também conhecidos por standard streams, que são representados por file descriptors (fd):
fd 0
: standard input, ou STDINfd 1
: standard output, ou STDOUTfd 2
: standard error, ou STDERR
STDOUT
Vamos analisar o seguinte comando:
O programa
echo
envia uma mensagem para o STDOUT, ou seja, file descriptor 1STDOUT refere-se ao screen do computador, e por isto a mensagem
Hello
é mostrada na tela
STDIN
Agora, vamos a outro exemplo com STDIN:
Este comando fica à espera de dados em uma interface interativa do STDIN, que refere-se ao teclado do computador.
Então, devemos digitar qualquer texto (neste caso digitei "leandro") e, para finalizar, devemos pressionar a tecla ENTER[CR] seguida de CTRL+d, que basicamente finaliza a interface STDIN. Após isto, o comando deve retornar o output:
O programa
base64
fica à espera do STDIN, ou seja, file descriptor 0STDIN refere-se ao teclado do computador, e por isto abre-se uma interface interativa para receber informação a partir do teclado
Digitei "leandro", pressionei ENTER e em seguida CTRL+d para sair da interface STDIN
O programa capturou a informação através do STDIN e converteu a informação para um formato base 64
O programa enviou a informação convertida em base 64 para o STDOUT
STDOUT refere-se ao screen do computador, e por isto o conteúdo base 64 é mostrado na tela
Interessante notar que programas tais como o base64
interagem tanto com o stream STDIN quanto o STDOUT.
STDERR
E se passarmos um argumento, por exemplo o nome de um arquivo inexistente para o comando base64
?
Como o programa fica à espera de informação a partir do STDIN, é lançado um erro caso o STDIN não proveja a informação.
Todo programa, por padrão, envia seus erros para a stream STDERR, representada pelo file descriptor 2.
E qual o dispositivo de saída do STDERR? É o mesmo do STDOUT, e justamente por este motivo conseguimos ver a mensagem de erro na tela!
Redirecionamento de streams
Recapitulando, sabemos que file descriptors (fd) são arquivos especiais do filesystem, mas para todo efeito, são arquivos.
E, uma vez que standard streams são file descriptors, será possível redirecionarmos, ou seja, mudarmos o destino de um stream para outro stream ou até mesmo qualquer outro arquivo do filesystem?
Sim, é possível, com o uso dos operadores >
e <
, utilizando o número do fd como prefixo.
Redirecionamento de STDIN:
<
, ou0<
Redirecionamento de STDOUT:
>
, ou1>
Redirecionamento de STDERR:
2>
Voltando ao exemplo do comando echo
, podemos redirecionar o STDOUT para outro arquivo, e desta forma, o output será enviado para o arquivo de redirecionamento:
Note que o output não foi mostrado, pois foi redirecionado para o arquivo name.txt
. Se executarmos o comando cat name.txt
, podemos ver o resultado no screen!
Voltando ao exemplo do base64, que tal redirecionarmos o STDIN default (dispositivo de teclas) para que seja a partir do arquivo contendo o nome?
Nice!
Um "açúcar sintático" no bash é que, quando quisermos redirecionar o STDIN ou STDOUT, não precisamos colocar o sufixo do file descriptor:
E se tentarmos com um arquivo não-existente?
Muito similar ao erro que tivemos anteriormente. Como o arquivo não é encontrado, é lançado um erro, que vai para o STDERR, que por sua vez é mostrado por default no screen.
Mas podemos redirecionar o STDERR também para um outro arquivo, tal como o STDOUT e STDIN?
Sim, mas no caso do STDERR, precisamos utilizar o sufixo do file
Confirmando que o conteúdo foi redirecionado para err.txt
:
Podemos também concentrar tanto output quanto erros num único arquivo:
O &1
significa o stream atual para o file descriptor 1, neste caso o arquivo out.log
.
Utilizando outros file descriptors
Com exceção dos fd padrão 0, 1, e 2, podemos criar outros file descriptors e utilizarmos como IPC? Sim, podemos! Vamos começar criando um diretório onde vamos armazenar estes fd temporários:
Vamos supor que queremos atribuir o fd 42
. Devemos então preparar nosso fd, que será um canal de comunicação de única via, ou single-communication channel entre dois processos.
Primeiro, abrimos o fd para para escrita >
(STDOUT):
Agora, redirecionamos uma mensagem para o fd utilizando redirecionamento de stream de escrita:
Então com o comando base64, e sabendo que podemos ler de qualquer fd com redirecionamento de streams, fazemos o redirecionamento de leitura:
File descriptors são recursos, portanto depois de utilizados, devem ser "liberados" no sistema operacional, ou seja, fechados tanto para escrita quanto leitura:
Resumo
Nesta seção, vimos como diferentes processos se comunicam utilizando uma forma primitiva de IPC, que são os file descriptors.
Uma vez que entendemos isto, já podemos ir para a próxima etapa que irá explorar outra forma de comunicação um pouco mais sofisticada, UNIX pipes.
Last updated