Искусство программирования на языке сценариев командной оболочки
Шрифт:
echo 1234567890 > File # Записать строку в файл "File".
exec 3<> File # Открыть "File" и связать с дескриптором 3.
read -n 4 <&3 # Прочитать 4 символа.
echo -n . >&3 # Записать символ точки.
exec 3>&- # Закрыть дескриптор 3.
cat File # ==> 1234.67890
# Произвольный доступ, да и только!
|
# Конвейер (канал).
# Универсальное средство для объединения команд в одну цепочку.
# Похоже на ">", но на самом деле -- более обширная.
# Используется
cat *.txt | sort | uniq > result-file
# Содержимое всех файлов .txt сортируется, удаляются повторяющиеся строки,
# результат сохраняется в файле "result-file".
Операции перенаправления и/или конвейеры могут комбинироваться в одной командной строке.
command < input-file > output-file
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>&-
Закрыть дескриптор выходного файла 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", как и следовало ожидать, принимает данные с обычного stdin.
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 "Невозможно прочитать из заданного файла!"