Файловые дескрипторы и сценарии оболочки

32

Мне очень трудно понять, как использовать файловые дескрипторы в сценариях оболочки.

Я знаю основы, такие как

exec 5 > /tmp/foo

Итак, fd 5 прикреплен к foo для записи.

exec 6 < /tmp/bar

… для чтения.

exec 5>&-

… Закрыть фд.

Теперь, что это делает?

#!/bin/bash

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

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

Как я понимаю, &5закрывает fd, так как же вывод успешно перенаправляется после каждого вызова?

Это копия пасты из: Здесь

Он утверждает, что использование этого поверх простого echo $a > fileсделает это намного быстрее, однако я не понимаю. Буду признателен за любые ссылки на достойный учебник. Я гугл полномочия, кажется, подводит меня.

Рико М
источник

Ответы:

44

Во-первых, обратите внимание, что синтаксис для закрытия равен 5>&-или 6<&-, в зависимости от того, читается ли дескриптор файла для записи или для чтения. Кажется, в этом посте есть опечатка или сбой форматирования.

Вот прокомментированный скрипт.

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                  # 

Здесь нет закрытия. Поскольку в этом простом примере все входы и выходы идут в одно и то же место, использование дополнительных файловых дескрипторов не является необходимым. Вы могли бы написать

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

Использование явных файловых дескрипторов становится полезным, если вы хотите записать несколько файлов по очереди. Например, рассмотрим сценарий, который выводит данные в файл вывода данных и записывает данные в файл журнала, а также, возможно, сообщения об ошибках. Это означает три выходных канала: один для данных, один для журналов и один для ошибок. Поскольку существует только два стандартных дескриптора для вывода, необходим третий. Вы можете позвонить, execчтобы открыть выходные файлы:

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

Замечание об эффективности появляется, когда у вас есть перенаправление в цикле, например так (предположим, файл пуст для начала):

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

На каждой итерации программа открывается /tmp/bar, ищет конец файла, добавляет некоторые данные и закрывает файл. Более эффективно открыть файл раз и навсегда:

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

Когда в разное время происходит несколько execперенаправлений, становится полезным вызов перенаправлений, а не упаковка блока в перенаправление.

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

Вы найдете несколько других примеров перенаправления, просмотрев io-redirectionтег на этом сайте .

Жиль "ТАК - перестань быть злым"
источник
1
Любой синтаксис для закрытия файлового дескриптора фактически делает то же самое.
user1338062 25.10.15