Большинство команд имеют один входной канал (стандартный ввод, дескриптор файла 0) и один выходной канал (стандартный вывод, дескриптор файла 1) или работают с несколькими файлами, которые они открывают сами (поэтому вы передаете им имя файла). (Это в дополнение к стандартной ошибке (fd 2), которая обычно фильтруется вплоть до пользователя.) Однако иногда удобно иметь команду, которая действует как фильтр от нескольких источников или нескольких целей. Например, вот простой скрипт, который отделяет нечетные строки в файле от четных
while IFS= read -r line; do
printf '%s\n' "$line"
if IFS= read -r line; then printf '%s\n' "$line" >&3; fi
done >odd.txt 3>even.txt
Теперь предположим, что вы хотите применить другой фильтр к строкам с нечетными номерами и к строкам с четными номерами (но не собирать их вместе, это было бы другой проблемой, неосуществимой в общем случае в оболочке). В оболочке вы можете передать стандартный вывод команды только другой команде; чтобы передать другой дескриптор файла, вам нужно сначала перенаправить его на fd 1.
{ while … done | odd-filter >filtered-odd.txt; } 3>&1 | even-filter >filtered-even.txt
Другой, более простой вариант использования - фильтрация вывода ошибок команды .
exec M>&N
перенаправляет файловый дескриптор на другой для оставшейся части сценария (или до тех пор, пока другая такая команда снова не изменит файловые дескрипторы). Существует некоторое совпадение в функциональности между exec M>&N
и somecommand M>&N
. exec
Форма является более мощным , что он не должен быть вложенными:
exec 8<&0 9>&1
exec >output12
command1
exec <input23
command2
exec >&9
command3
exec <&8
Другие примеры, которые могут представлять интерес:
И еще больше примеров:
PS Это удивительный вопрос от автора самого популярного поста на сайте, который использует перенаправление через fd 3 !
Жиль "ТАК - перестань быть злым"
источник
while IFS= read -r line;
? На мой взгляд, IFS здесь не действует, так как вы присваиваете значение только одной переменной ( строке ). Смотрите этот вопрос.IFS
имеет значение, даже если вы читаете в одну переменную (это для сохранения лидирующего пробела).sed -ne 'w odd.txt' -e 'n;w even.txt'
?Вот пример использования дополнительных FD в качестве контроля чата bash-скрипта:
источник
В контексте именованных каналов (fifos) использование дополнительного файлового дескриптора может включить неблокирующее поведение конвейера.
Смотрите: Named Pipe преждевременно закрывается в скрипте?
источник
Дополнительный файловый дескриптор подходит для случаев, когда вы хотите перехватить стандартный вывод в переменной, но все же хотите вывести его на экран, например, в пользовательском интерфейсе bash-скрипта.
источник
Вот еще один сценарий, когда использование дополнительного файлового дескриптора кажется подходящим (в Bash):
Защита паролем сценария командной строки параметров командной строки
источник
Пример: использование flock для принудительного запуска сценариев с блокировками файлов
Одним из примеров является использование блокировки файлов для принудительного запуска сценариев по всей системе. Это полезно, если вы не хотите, чтобы два скрипта одного типа работали с одинаковыми файлами. В противном случае два сценария будут мешать друг другу и, возможно, повреждать данные.
Функционально использовать стадо, определив блокировку и разблокировку
Вы также можете обернуть эту логику блокировки / разблокировки в многократно используемые функции. Следующая
trap
встроенная оболочка автоматически снимет блокировку файла при выходе из скрипта (либо ошибка, либо успех).trap
помогает очистить файл блокировки. Путь/tmp/file.lock
должен быть жестко закодированным, чтобы несколько скриптов могли попытаться заблокировать его.unlock
Логика выше , чтобы удалить файл до снятия блокировки. Таким образом, он очищает файл блокировки. Поскольку файл был удален, другой экземпляр этой программы может получить блокировку файла.Использование функций блокировки и разблокировки в скриптах
Вы можете использовать его в своих скриптах, как в следующем примере.
Если вы хотите, чтобы ваш код ожидал блокировки, вы можете настроить скрипт следующим образом:
источник
В качестве конкретного примера я только что написал сценарий, которому нужна информация о синхронизации из подкоманды. Использование дополнительного файлового дескриптора позволило мне захватить
time
stderr команды, не прерывая stdout или stderr подкоманды.Для этого нужно указать
ls
stderr на fd 3, указать fd 3 на stderr скрипта и указатьtime
stderr на файл. Когда скрипт выполняется, его stdout и stderr совпадают с подкомандой, которую можно перенаправить как обычно. Толькоtime
выходные данные перенаправляются в файл.источник