написано Stephane Chazelas и дополнено автором документа
Практически любая команда предполагает доступность 3-х файловых дескрипторов. Первый — 0 (стандвртный ввод, stdin), доступный для чтения. И два других — 1 (stdout) и 2 (stderr), доступные для записи.
Запись, типа ls 2>&1, означает временное перенаправление вывода, с устройства stderr на устройство stdout.
В соответствии с соглашениями, команды принимают ввод из файла с дескриптором 0 (stdin), выводят результат работы в файл с дескриптором 1 (stdout), а сообщения об ошибках — в файл с дескриптором 2 (stderr). Если какой либо из этих трех дескрипторов окажется закрытым, то могут возникнуть определенные проблемы:
-
bash$ cat /etc/passwd >&—
-
cat: standard output: Bad file descriptor
-
К примеру, когда пользователь запускает xterm, то он сначала выполняет процедуру инициализации, а затем, перед запуском командной оболочки, xterm трижды открывает терминальные устройства (/dev/pts/<n>, или нечто подобное).
После этого, командная оболочка наследует эти три дескриптора, и любая команда, запускаемая в этой оболочке, так же наследует их. Термин перенаправление — означает переназначение одного файлового дескриптора на другой (канал (конвейер) или что-то другое). Переназначение может быть выполнено локально (для отдельной команды, для группы команд, для подоболочки, для операторов while, if, case, for…) или глобально (с помощью exec).
ls > /dev/null — означает запуск команды ls с файловым дескриптором 1, присоединенным к устройству /dev/null.
-
bash$ lsof -a -p $$ -d0,1,2
-
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
-
bash 363 bozo 0u CHR 136,1 3 /dev/pts/1
-
bash 363 bozo 1u CHR 136,1 3 /dev/pts/1
-
bash 363 bozo 2u CHR 136,1 3 /dev/pts/1
-
bash$ exec 2> /dev/null
-
bash$ lsof -a -p $$ -d0,1,2
-
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
-
bash 371 bozo 0u CHR 136,1 3 /dev/pts/1
-
bash 371 bozo 1u CHR 136,1 3 /dev/pts/1
-
bash 371 bozo 2w CHR 1,3 120 /dev/null
-
bash$ bash -c ‘lsof -a -p $$ -d0,1,2’ | cat
-
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
-
lsof 379 root 0u CHR 136,1 3 /dev/pts/1
-
lsof 379 root 1w FIFO 0,0 7118 pipe
-
lsof 379 root 2u CHR 136,1 3 /dev/pts/1
-
bash$ echo «$(bash -c ‘lsof -a -p $$ -d0,1,2’ 2>&1)«
-
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
-
lsof 426 root 0u CHR 136,1 3 /dev/pts/1
-
lsof 426 root 1w FIFO 0,0 7520 pipe
-
lsof 426 root 2w FIFO 0,0 7520 pipe
Упражнение: Проанализируйте следующий сценарий.
-
#! /usr/bin/env bash
-
mkfifo /tmp/fifo1 /tmp/fifo2
-
while read a; do echo «FIFO1: $a«; done < /tmp/fifo1 &
-
exec 7> /tmp/fifo1
-
exec 8> >(while read a; do echo «FD8: $a, to fd7″; done >&7)
-
exec 3>&1
-
(
-
(
-
(
-
while read a; do echo «FIFO2: $a«; done < /tmp/fifo2 | tee /dev/stderr | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 &
-
exec 3> /tmp/fifo2
-
echo 1st, to stdout
-
sleep 1
-
echo 2nd, to stderr >&2
-
sleep 1
-
echo 3rd, to fd 3 >&3
-
sleep 1
-
echo 4th, to fd 4 >&4
-
sleep 1
-
echo 5th, to fd 5 >&5
-
sleep 1
-
echo 6th, through a pipe | sed ‘s/.*/PIPE: &, to fd 5/’ >&5
-
sleep 1
-
echo 7th, to fd 6 >&6
-
sleep 1
-
echo 8th, to fd 7 >&7
-
sleep 1
-
echo 9th, to fd 8 >&8
-
) 4>&1 >&3 3>&— | while read a; do echo «FD4: $a«; done 1>&3 5>&— 6>&—
-
) 5>&1 >&3 | while read a; do echo «FD5: $a«; done 1>&3 6>&—
-
) 6>&1 >&3 | while read a; do echo «FD6: $a«; done 3>&—
-
rm -f /tmp/fifo1 /tmp/fifo2
-
# Выясните, куда переназначены файловые дескрипторы каждой команды и подоболочки.
-
exit 0
- Страница для печати
- 10104 просмотра