Когда Вы использовали бы дополнительный дескриптор файла?

Если Вы не можете или не хотеть использовать файл версии LSB (из-за зависимостей, пакет вводит), можно искать определенные для дистрибутива файлы версии. Bcfg2 имеет датчик для дистрибутива, который Вы смогли использовать: http://trac.mcs.anl.gov/projects/bcfg2/browser/doc/server/plugins/probes/group.txt

76
14.10.2015, 01:01
6 ответов

Большинство команд имеет единственный канал ввода (стандартный вход, дескриптор файла 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

Другие примеры, которые могут представлять интерес:

И еще для большего количества примеров:

P.S. Это - удивительный вопрос, прибывающий от автора большей части сообщения upvoted на сайте, который использует перенаправление через fd 3!

53
27.01.2020, 19:31
  • 1
    я сказал бы, что "большинство команд имеет или единственный или двойной канал вывода - stdout (fd 1) и очень часто stderr (fd 2)". –  rozcietrzewiacz 17.08.2011, 18:15
  • 2
    Кроме того, могли Вы между прочим объяснять, почему Вы используете while IFS= read -r line;? Путем я вижу его, IFS не имеет никакого эффекта здесь, так как Вы присваиваете значение только одной переменной (строка). Посмотрите этот вопрос. –  rozcietrzewiacz 17.08.2011, 18:33
  • 3
    @rozcietrzewiacz я сделал упоминание о stderr и вижу первую часть моего ответа для почему IFS имеет значение, даже если Вы читаете в единственную переменную (она должна сохранить ведущий пробел). –  Gilles 'SO- stop being evil' 18.08.2011, 04:26
  • 4
    Не Могли Вы делать то же с sed -ne 'w odd.txt' -e 'n;w even.txt'? –  Wildcard 23.11.2017, 02:07
  • 5
    @Wildcard, Вы могли сделать то же с другими инструментами, уверенными. Но цель этого ответа состояла в том, чтобы проиллюстрировать перенаправления в оболочке. –  Gilles 'SO- stop being evil' 23.11.2017, 14:12

В контексте именованных каналов (fifos) использование дополнительного дескриптора файла может позволить не блокировать поведение передачи по каналу.

(
rm -f fifo
mkfifo fifo
exec 3<fifo   # open fifo for reading
trap "exit" 1 2 3 15
exec cat fifo | nl
) &
bpid=$!

(
exec 3>fifo  # open fifo for writing
trap "exit" 1 2 3 15
while true;
do
    echo "blah" > fifo
done
)
#kill -TERM $bpid

См.: Именованный канал, закрывающийся преждевременно в сценарии?

8
27.01.2020, 19:31
  • 1
    Вы вскопали один из моих старых вопросов :) Чад, является правильным, Вы столкнетесь с состоянием состязания. –  n0pe 17.08.2011, 14:57

Вот еще один сценарий, когда использование дополнительного дескриптора файла кажется соответствующим (в Bash):

Безопасность пароля сценария оболочки параметров командной строки

env -i bash --norc   # clean up environment
set +o history
read -s -p "Enter your password: " passwd
exec 3<<<"$passwd"
mycommand <&3  # cat /dev/stdin in mycommand
3
27.01.2020, 19:31
[1186088] Дополнительный файловый дескриптор хорош для тех случаев, когда вы хотите перехватить stdout в переменной, но все равно хотите записать на экран, например, в пользовательском интерфейсе бэш-скрипта

6
27.01.2020, 19:31

Вот пример использования дополнительных FD в качестве контроля разговора в сценарии bash:

#!/bin/bash

log() {
    echo $* >&3
}
info() {
    echo $* >&4
}
err() {
    echo $* >&2
}
debug() {
    echo $* >&5
}

VERBOSE=1

while [[ $# -gt 0 ]]; do
    ARG=$1
    shift
    case $ARG in
        "-vv")
            VERBOSE=3
        ;;
        "-v")
            VERBOSE=2
        ;;
        "-q")
            VERBOSE=0
        ;;
        # More flags
        *)
        echo -n
        # Linear args
        ;;
    esac
done

for i in 1 2 3; do
    fd=$(expr 2 + $i)
    if [[ $VERBOSE -ge $i ]]; then
        eval "exec $fd>&1"
    else
        eval "exec $fd> /dev/null"
    fi
done

err "This will _always_ show up."
log "This is normally displayed, but can be prevented with -q"
info "This will only show up if -v is passed"
debug "This will show up for -vv"
13
27.01.2020, 19:31

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

Этот ответ stackexchange (, модифицированный , этот)дает изящное решение для создания временного файла в сценарии оболочки. Файл существует только до тех пор, пока дескриптор файла открыт, поэтому файл удаляется даже в случае сбоя программы. При использовании отдельных файловых дескрипторов для чтения и записи указатель файла «чтение» будет находиться в начале файла даже после того, как указатель файла «записи» переместится в конец файла.

tmpfile=$(mktemp)
exec 3> "$tmpfile"
exec 4< "$tmpfile"
rm "$tmpfile"

echo "foo" >&3
cat <&4
1
30.04.2020, 23:23

Теги

Похожие вопросы