нетривиальна, но по крайней мере для повседневных нужд достаточно придерживаться основного правила: никогда не экспортируйте временные переменные, служащие для краткосрочных целей, и всегда экспортируйте переменные, необходимые вам во всех порожденных интерпретаторах (включая, например, интерпретаторы, запускаемые командой !
редактора ed
). Поэтому переменные, имеющие специальное значение для интерпретатора, такие, как PATH
и НОМЕ
, следует экспортировать.Упражнение 3.13Почему в значение переменной
PATH
всегда включается текущий каталог? Куда его нужно поместить?3.7 Еще раз о переключении ввода-вывода
Понятие стандартного потока диагностики было введено для того, чтобы сообщения об ошибках всегда появлялись на терминале:
$ diff file1 file2 >diff.out
diff: file2: No such file or directory
$
Без сомнения, сообщения об ошибке должны появляться подобным образом — было бы крайне неприятно, если бы они исчезли в файле
diff.out
, оставляя вас в уверенности, что ошибочная команда diff
выполнена правильно.В начале выполнения каждой программы определены по умолчанию три файла, обозначаемые небольшими целыми числами и называемые дескрипторами файла (мы рассмотрим их в гл. 7). Со стандартными входным (0) и выходным (1) потоками вы уже знакомы: они часто переключаются на файл или программный канал. Последний поток с номером 2 представляет собой стандартный поток диагностики и обычно предназначается для вывода на терминал.
Иногда программы осуществляют вывод в стандартный поток диагностики, даже если они работают правильно. Типичным примером является программа time, которая выполняет команду и выдает в стандартный поток диагностики сообщение о том, сколько времени заняло выполнение:
$ time wc ch3.1
931 4288 22691 ch3.1
real 1.0
user 0.4
sys 0.4
$ time wc ch3.1 >wc.out
real 2.0
user 0.4
sys 0.3
$ time wc ch3.1 >wc.out 2>time.out
$ cat time.out
real 1.0
user 0.4
sys 0.3
$
Конструкция
2> имя_файла
(между 2
и >
не должно быть пробелов) переключает стандартный поток диагностики на файл; синтаксически она непривлекательна, но служит своей цели. (Для такого короткого теста, как приведенный выше, время, выдаваемое командой time
, не совсем правильное, но для последовательности больших тестов она выводит полезную информацию, которой можно доверять в разумных границах. Вы вполне можете сохранить ее для дальнейшего анализа; обратитесь, например, к таблице 8.1.)Допустимо также слияние двух выходных потоков:
$ time wc ch3.1 >wc.out 2>&1
$ cat wc.out
931 4288 22691 ch3.1
real 1.0
user 0.4
sys 0.3
$
Обозначение
2>&1
является указанием интерпретатору, что стандартный поток диагностики нужно поместить в тот же поток, что и стандартный выходной. Амперсанд не содержит какого-либо мнемонического смысла; это просто идиома, которую следует запомнить. Для добавления стандартного выходного потока к стандартному потоку диагностики можно использовать 1>&2
:echo ... 1>&2
В командных файлах это позволяет предотвратить исчезновение сообщений в файле или программном канале.
Интерпретатор предоставляет возможность размещать стандартный входной поток вместе с командой, а не в отдельном файле, так что командный файл может хранить всю информацию в себе самом. Наша справочная программа
411
, работающая с каталогом телефонов, могла быть задана так:$ cat 411
grep "$*" <
dial-a-joke 212-976-3838
dial-a-prayer 212-246-4200
dial santa 212-976-3636
dow jones report 212-976-4141
End
$
Программирующие на языке
shell
называют такую конструкцию "документ здесь", т.е. входной поток находится здесь, а не в каком-нибудь файле. Началом конструкции служит <<
; последующее слово (в нашем примере End
) является ограничителем входного потока, включающего все строки до той, которая содержит только данное слово. Интерпретатор выполняет замену конструкций $
, `...`
и \
в "документе здесь", если только часть слова не экранирована кавычками или обратной дробной чертой, — в этом случае весь документ берется без изменений. В конце главы мы рассмотрим еще более интересный пример с конструкцией "документ здесь".В табл. 3.2 перечислены различные виды переключения ввода-вывода, допускаемые интерпретатором.
> файл
Переключение стандартного выходного потока в файл >> файл
Добавление стандартного выходного потока в файл < файл
Получение стандартного выходного потока из файла p1 | p2
Передача стандартного выходного потока программы p1
в качестве входного потока для программы p2
^
Устарелый синоним |
n> файл
Переключение выходного потока из файла с дескриптором n в файл n>> файл
Добавление выходного потока из файла с дескриптором n в файл n>&m
Слияние выходных потоков файлов с дескрипторами n
и m
<
"Документ здесь": берется стандартный входной поток до строки, начинающейся с s
; выполняется подстановка для $
, `...`
и \
<<\s
"Документ здесь" без подстановки <<'s'
"Документ здесь" без подстановки
Таблица 3.2: Переключение ввода-вывода интерпретатора
Упражнение 3.14Сравните версии программы 411: использующую "документ здесь" и первоначальную. Какую легче сопровождать? Какая более подходит в качестве основы общего служебного средства?
3.8 Циклы в shell-программах
Язык
shell
— действительно язык программирования: в нем есть переменные, циклы, ветвления и т.п. Здесь мы обсудим основные циклы, а структуры управления рассмотрим более подробно в гл. 5.Типичным считается цикл по последовательности имен файлов, и оператор
for
языка shell
является единственной структурой управления, которую обычно задают с терминала, а не помещают в файл для последующего выполнения. Синтаксис оператора for
таков:for перем in список_слов
do
команды
done
Например, для получения эха имен файлов по одному на строке достаточно задать:
$ for i in *
> do
> echo $i
> done
Вместо
i
можно применять любую переменную языка