Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 2:

Язык shell

Перенаправление ввода/вывода

Командный интерпретатор shell ассоциирует с каждым открытым файлом так называемый дескриптор. Дескрипторы нумеруются десятичными целыми числами, начиная с нуля. Верхняя граница зависит от реализации, но, согласно стандарту POSIX, должны поддерживаться по крайней мере десять одновременно открытых файлов (с номерами дескрипторов от 0 до 9 включительно).

Дескрипторы с номерами 0, 1 и 2 имеют специальный смысл. Они соответствуют стандартному вводу, стандартному выводу и стандартному протоколу.

Перед выполнением команды ее ввод и вывод могут быть перенаправлены, для чего используется специальная нотация, которую интерпретирует shell. Описанные ниже конструкции располагаются в любом месте простой команды, предшествуют команде или завершают ее и не передаются в качестве аргументов команды; если они завершают определение функции, то воздействуют на все команды тела, не производящие собственных перенаправлений.

Перенаправление ввода:

<слово

Использовать файл слово для стандартного ввода ( дескриптор файла 0).

Перенаправление вывода с перезаписью:

>слово
>|слово

Использовать файл слово для стандартного вывода (дескриптор файла 1). Имеющийся файл опустошается, а если файла нет, он создается. (При использовании первой разновидности перенаправления вывода в некоторых случаях попытка перезаписи существующего файла является ошибкой; см. далее описание опции -C команды set.)

Перенаправление вывода с дозаписью:

>>слово

Использовать файл слово для стандартного вывода. Если файл существует, то выводимая информация добавляется в конец (сначала производится поиск конца файла); в противном случае файл создается. Если любой из этих конструкций предшествует цифра, она определяет дескриптор (вместо подразумеваемых дескрипторов 0 или 1), который будет ассоциирован с файлом, указанным в конструкции. Например, строка

...  2>protocol

перенаправляет стандартный протокол (дескриптор 2) в файл по имени protocol.

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

<&номер_дескриптора
>&номер_дескриптора

Например, чтобы перенаправить стандартный протокол туда же, куда назначен стандартный вывод, употребить конструкцию

...  2>&1

Если в качестве номера_дескриптора указан минус (' - '), соответствующий файл (стандартный ввод, вывод или явно заданный своим дескриптором файл) закрывается.

Shell позволяет открыть файл одновременно на чтение и запись при помощи конструкции

<>слово

Ей, как всегда, может предшествовать номер дескриптора для открываемого файла. По умолчанию используется 0, то есть стандартный ввод.

Приведем два примера. Пусть нужно измерить время выполнения некоторой команды, направив ее результаты в файл cmd.res, а данные о времени - в файл cmd.time. К цели ведет строка, приведенная в листинге 2.24:

time  команда  >cmd.res  2>cmd.time
Листинг 2.24. Пример перенаправления стандартного вывода и стандартного протокола.

Второй пример. Рассмотрим цикл, описанный в листинге 2.25:

i=0
while [ $i -lt 40 ]
do
 > lost+found/g$i
 i=$(($i+1))
done
rm lost+found/g*
Листинг 2.25. Пример перенаправления стандартного вывода пустой команды.

С его помощью создается 40 файлов в каталоге lost+found, которые затем удаляются. Отметим, что перенаправляется стандартный вывод пустой команды, а в результате создается пустой файл.

(Поясним смысл приведенного фрагмента. При проверке и коррекции файловой системы утилитой fsck в каталог /lost+found помещаются непустые файлы, на которые нет ссылок. Сложность в том, что пока утилита fsck работает, ни один файл не должен расширяться, т. е. в каталоге /lost+found должны быть заранее заготовленные пустые места.)

Shell дает возможность размещать исходные данные в виде вставки в интерпретируемый командный файл, для чего употребляются многострочные конструкции:

<<слово
 вставка
слово

и

<<-слово
 вставка
слово

Их можно считать разновидностями перенаправления ввода. На вход команды подается вставка, представляющая собой череду строк вплоть до слова, указанного при перенаправлении. Второй вариант отличается тем, что из строк вставки удаляются начальные символы табуляции.

В качестве примера использования вставок приведем файл ОС Linux /etc/tripwire/twinstall.sh, который содержит следующие фрагменты (см. листинг 2.26 и листинг 2.27):

cat << END_OF_TEXT
A clear-text version of the Tripwire 
configuration file
$TXT_CFG
has been preserved for your inspection.  
It is recommended that you delete this 
file manually after you have examined it.
END_OF_TEXT
Листинг 2.26. Пример использования вставки.
cat <<eof1; cat <<eof2
Вставка 1
eof1
Вставка 2
eof2
Листинг 2.27. Пример использования двух последовательных вставок.

В результате выполнения второго фрагмента будут выданы две строки:

Вставка 1
Вставка 2

Экранирование

Под экранированием имеется в виду защита символов от интерпретации со стороны языка shell. Следующие символы shell трактует по-особому; не будучи экранированными, они завершают предшествующее им слово:

|  &  ;  <  >  (  )  $  `  \  "  '  
пробел  перевод_строки

Не являясь разделителями слов, особую роль играют для shell и символы

*  ?  [  ]  #  ~  =  %

Каждый из перечисленных выше символов может быть экранирован, т. е. представлять самого себя, если перед ним стоит \ либо он расположен между одиночными или двойными кавычками ( '' или "" ).

Экранирование с помощью двойных кавычек имеет некоторые особенности. Во-первых, оно не отменяет особой трактовки символов $ и `. Иными словами, внутри двойных кавычек обычным образом выполняется подстановка значений переменных, результатов выполнения команд и результатов вычисления арифметических выражений, только результат подстановки расценивается как одно слово. Во-вторых, особая трактовка символа \ отменяется внутри двойных кавычек лишь частично: символ \ сохраняет экранирующую роль, если после него следуют:

$  `  "  \  перевод_строки

Приведем несколько примеров использования двойных кавычек для экранирования. В первом команда

echo "$(echo *)"

выдаст список файлов текущего каталога, а во втором результатом выполнения строки

echo "$(echo "*")"

станет звездочка. Если же аргумент " $(echo *) " предложить усовершенствованной процедуре three_args, то число фактических аргументов окажется равным единице, а список файлов текущего каталога станет значением первого аргумента.

Рассмотрим третий пример. Пусть нужно выдать информацию о всех файлах текущего каталога, которые модифицировались последний раз 3 октября. Конвейер

ls -al | grep "Oct  3"

сделает то, что нужно (служебная программа grep выполняет сопоставление заданного шаблона со строками заданных файлов или стандартного ввода). Кавычки использованы для экранирования двух пробелов в разыскиваемой цепочке символов. Без экранирования пробелы превращаются в разделители аргументов, и команда grep попыталась бы найти текст Oct в файле с цифровым именем 3.

Еще один пример. Запись

$(($i\*5))

синтаксически неверна, поскольку в арифметических выражениях shell рассматривает звездочку как операцию умножения, а не как элемент шаблона имен файлов; соответственно, она не нуждается в экранировании, и символ \ становится лишним, нарушая синтаксис выражения. Таким образом, лишнее экранирование может быть вредным.

Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?