Искусство программирования на языке сценариев командной оболочки
Шрифт:
command1 | command2 | command3 > output-file
См. Пример 12-23 и Пример A-17.
Допускается перенаправление нескольких потоков в один файл.
ls -yz >> command.log 2>&1
# Сообщение о неверной опции "yz" в команде "ls" будет записано в файл "command.log".
# Поскольку stderr перенаправлен в файл.
Закрытие дескрипторов файлов
n<&-
Закрыть дескриптор входного файла n.
0<&-, <&-
Закрыть stdin.
n>&-
Закрыть
1>&-, >&-
Закрыть stdout.
Дочерние процессы наследуют дескрипторы открытых файлов. По этой причине и работают конвейеры. Чтобы предотвратить наследование дескрипторов -- закройте их перед запуском дочернего процесса.
# В конвейер передается только stderr.
exec 3>&1 # Сохранить текущее "состояние" stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Закрыть дескр. 3 для 'grep' (но не для 'ls').
# ^^^^ ^^^^
exec 3>&- # Теперь закрыть его для оставшейся части сценария.
# Спасибо S.C.
Дополнительные сведения о перенаправлении ввода/вывода вы найдете в Приложение D.
16.1. С помощью команды exec
Команда exec <filename перенаправляет ввод со stdin на файл. С этого момента весь ввод, вместо stdin (обычно это клавиатура), будет производиться из этого файла. Это дает возможность читать содержимое файла, строку за строкой, и анализировать каждую введенную строку с помощью sed и/или awk.
Пример 16-1. Перенаправление stdin с помощью exec
#!/bin/bash
# Перенаправление stdin с помощью 'exec'.
exec 6<&0 # Связать дескр. #6 со стандартным вводом (stdin).
# Сохраняя stdin.
exec < data-file # stdin заменяется файлом "data-file"
read a1 # Читается первая строка из "data-file".
read a2 # Читается вторая строка из "data-file."
echo
echo "Следующие строки были прочитаны из файла."
echo "-----------------------------------------"
echo $a1
echo $a2
echo; echo; echo
exec 0<&6 6<&-
# Восстанавливается stdin из дескр. #6, где он был предварительно сохранен,
#+ и дескр. #6 закрывается ( 6<&- ) освобождая его для других процессов.
#
# <&6 6<&- дает тот же результат.
echo -n "Введите строку "
read b1 # Теперь функция "read", как и следовало ожидать, принимает
echo "Строка, принятая со stdin."
echo "--------------------------"
echo "b1 = $b1"
echo
exit 0
Аналогично, конструкция exec >filename перенаправляет вывод на stdout в заданный файл. После этого, весь вывод от команд, который обычно направляется на stdout, теперь выводится в этот файл.
Пример 16-2. Перенаправление stdout с помощью exec
#!/bin/bash
# reassign-stdout.sh
LOGFILE=logfile.txt
exec 6>&1 # Связать дескр. #6 со stdout.
# Сохраняя stdout.
exec > $LOGFILE # stdout замещается файлом "logfile.txt".
# ----------------------------------------------------------- #
# Весь вывод от команд, в данном блоке, записывается в файл $LOGFILE.
echo -n "Logfile: "
date
echo "-------------------------------------"
echo
echo "Вывод команды \"ls -al\""
echo
ls -al
echo; echo
echo "Вывод команды \"df\""
echo
df
# ----------------------------------------------------------- #
exec 1>&6 6>&- # Восстановить stdout и закрыть дескр. #6.
echo
echo "== stdout восстановлено в значение по-умолчанию == "
echo
ls -al
echo
exit 0
Пример 16-3. Одновременное перенаправление устройств, stdin и stdout, с помощью команды exec
#!/bin/bash
# upperconv.sh
# Преобразование символов во входном файле в верхний регистр.
E_FILE_ACCESS=70
E_WRONG_ARGS=71
if [ !
– r "$1" ] # Файл доступен для чтения?
then
echo "Невозможно прочитать из заданного файла!"
echo "Порядок использования: $0 input-file output-file"
exit $E_FILE_ACCESS
fi # В случае, если входной файл ($1) не задан
#+ код завершения будет этим же.
if [ -z "$2" ]
then
echo "Необходимо задать выходной файл."
echo "Порядок использования: $0 input-file output-file"
exit $E_WRONG_ARGS
fi
exec 4<&0
exec < $1 # Назначить ввод из входного файла.
exec 7>&1