Descritores de arquivos e scripts de shell

27

Estou tendo muita dificuldade em entender como usar descritores de arquivos em scripts de shell.

Eu conheço o básico, como

exec 5 > /tmp/foo

Então o fd 5 está anexado ao foo para escrever.

exec 6 < /tmp/bar

… para leitura.

exec 5>&-

… close fd.

Agora, o que isso faz?

#!/bin/bash

exec 5 > /tmp/foo 
exec 6 < /tmp/bar 

cat <&6 | while read a
do
     echo $a >&5
done

Como eu entendo, &5 fecha o fd, então como a saída ainda está sendo redirecionada com sucesso após cada chamada?

Esta é uma cópia em massa de: Aqui

Ele afirma que usar isso em um simples echo $a > file seria muito mais rápido, mas eu não consigo entender. Eu gostaria de receber links para o tutorial decente. Eu os poderes do Google parecem estar falhando comigo.

    
por Ricko M 25.05.2011 / 00:08

1 resposta

40

Primeiro, observe que a sintaxe de fechamento é 5>&- ou 6<&- , dependendo se o descritor de arquivo está sendo lido para gravação ou para leitura. Parece haver um erro de digitação ou falha de formatação nesse post do blog.

Este é o script comentado.

exec 5>/tmp/foo       # open /tmp/foo for writing, on fd 5
exec 6</tmp/bar       # open /tmp/bar for reading, on fd 6
cat <&6 |             # call cat, with its standard input connected to
                      # what is currently fd 6, i.e., /tmp/bar
while read a; do      # 
  echo $a >&5         # write to fd 5, i.e., /tmp/foo
done                  # 

Não há fechamento aqui. Como todas as entradas e saídas estão indo para o mesmo lugar neste exemplo simples, o uso de descritores de arquivos extras não é necessário. Você poderia escrever

cat </tmp/bar |
while read a; do
  echo $a
done >/tmp/foo

O uso de descritores de arquivos explícitos se torna útil quando você deseja gravar em vários arquivos. Por exemplo, considere um script que envia dados para um arquivo de saída de dados e registra dados em um arquivo de log e, possivelmente, também em mensagens de erro. Isso significa três canais de saída: um para dados, um para logs e um para erros. Como existem apenas dois descritores padrão para a saída, um terceiro é necessário. Você pode chamar exec para abrir os arquivos de saída:

exec >data-file
exec 3>log-file
echo "first line of data"
echo "this is a log line" >&3
…
if something_bad_happens; then echo error message >&2; fi
exec >&-  # close the data output file
echo "output file closed" >&3

A observação sobre eficiência vem quando você tem um redirecionamento em um loop, como este (suponha que o arquivo esteja vazio para começar):

while …; do echo $a >>/tmp/bar; done

Em cada iteração, o programa abre /tmp/bar , procura o final do arquivo, acrescenta alguns dados e fecha o arquivo. É mais eficiente abrir o arquivo de uma vez por todas:

while …; do echo $a; done >/tmp/bar

Quando há vários redirecionamentos acontecendo em momentos diferentes, é útil chamar exec para executar redirecionamentos em vez de agrupar um bloco em um redirecionamento.

exec >/tmp/bar
while …; do echo $a; done

Você encontrará vários outros exemplos de redirecionamento navegando na tag io-redirection neste site .

    
por 25.05.2011 / 01:39