Descritores de arquivo e script de shell

32

Estou com muita dificuldade para entender como usar descritores de arquivo em scripts de shell.

Eu sei o básico, como

exec 5 > /tmp/foo

Então o fd 5 é anexado ao foo para escrever.

exec 6 < /tmp/bar

… para ler.

exec 5>&-

... fechar 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

Pelo que entendi &5fecha o fd, então como a saída ainda está sendo redirecionada com êxito após cada chamada?

Esta é uma cópia da pasta: Aqui

Alega que usar isso em um simples echo $a > filetornaria muito mais rápido, mas eu não entendo. Eu apreciaria todos os links para o tutorial decente. Eu google poderes parecem estar falhando comigo.

Ricko M
fonte

Respostas:

44

Primeiro, observe que a sintaxe para 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 formatação nessa postagem do blog.

Aqui está 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 local neste exemplo simples, o uso de descritores de arquivo 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 arquivo explícitos se torna útil quando você deseja gravar em vários arquivos por vez. Por exemplo, considere um script que produz dados para um arquivo de saída de dados e registre dados em um arquivo de log e, possivelmente, também mensagens de erro. Isso significa três canais de saída: um para dados, um para logs e outro para erros. Como existem apenas dois descritores padrão para saída, um terço é necessário. Você pode ligar execpara 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 aparece 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

A cada iteração, o programa é aberto /tmp/bar, procura o final do arquivo, anexa 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, a chamada execpara executar redirecionamentos em vez de agrupar um bloco em um redirecionamento se torna útil.

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

Você encontrará vários outros exemplos de redirecionamento navegando na io-redirectiontag deste site .

Gilles 'SO- parar de ser mau'
fonte
1
Qualquer sintaxe para fechar o descritor de arquivo realmente faz a mesma coisa.
user1338062