Искусство программирования на языке сценариев командной оболочки - Мендель Купер
Шрифт:
Интервал:
Закладка:
s/^ */
/g
Эта инструкция заменит начальные пробелы в строке на символ перевода строки. Ожидаемый результат -- замена отступов в начале параграфа пустыми строками.
Указание диапазона строк, предшествующее одной, или более, инструкции может потребовать заключения инструкций в фигурные скобки, с соответствующими символами перевода строки.
/[0-9A-Za-z]/,/^$/{
/^$/d
}
В этом случае будут удалены только первые из нескольких, идущих подряд, пустых строк. Это может использоваться для установки однострочных интервалов в файле, оставляя, при этом, пустые строки между параграфами.
Быстрый способ установки двойных межстрочных интервалов в текстовых файлах -- sed G filename.
Примеры использования sed в сценариях командной оболочки, вы найдете в:
1. Пример 33-1
2. Пример 33-2
3. Пример 12-2
4. Пример A-3
5. Пример 12-12
6. Пример 12-20
7. Пример A-13
8. Пример A-19
9. Пример 12-24
10. Пример 10-9
11. Пример 12-33
12. Пример A-2
13. Пример 12-10
14. Пример 12-8
15. Пример A-11
16. Пример 17-11
Ссылки на дополнительные сведения о sed, вы найдете в разделе Литература.
B.2. Awk
Awk -- это полноценный язык обработки текстовой информации с синтаксисом, напоминающим синтаксис языка C. Он обладает довольно широким набором возможностей, однако, мы рассмотрим лишь некоторые из них -- наиболее употребимые в сценариях командной оболочки.
Awk "разбивает" каждую строку на отдельные поля. По-умолчанию, поля -- это последовательности символов, отделенные друг от друга пробелами, однако имеется возможность назначения других символов, в качестве разделителя полей. Awk анализирует и обрабатывает каждое поле в отдельности. Это делает его идеальным инструментом для работы со структурированными текстовыми файлами, осбенно с таблицами.
Внутри сценариев командной оболочки, код awk, заключается в "строгие" (одиночные) кавычки и фигурные скобки.
awk '{print $3}' $filename
# Выводит содержимое 3-го поля из файла $filename на устройство stdout.
awk '{print $1 $5 $6}' $filename
# Выводит содержимое 1-го, 5-го и 6-го полей из файла $filename.
Только что, мы рассмотрели действие команды print. Еще, на чем мы остановимся -- это переменные. Awk работает с переменными подобно сценариям командной оболочки, но более гибко.
{ total += ${column_number} }
Эта команда добавит содержимое переменной column_number к переменной "total". Чтобы, в завершение вывести "total", можно использовать команду END, которая открывает блок кода, отрабатывающий после того, как будут обработаны все входные данные.
END { print total }
Команде END, соответствует команда BEGIN, которая открывает блок кода, отрабатывающий перед началом обработки входных данных.
Примеры использования awk в сценариях командной оболочки, вы найдете в:
1. Пример 11-10
2. Пример 16-7
3. Пример 12-24
4. Пример 33-3
5. Пример 9-22
6. Пример 11-16
7. Пример 27-1
8. Пример 27-2
9. Пример 10-3
10. Пример 12-42
11. Пример 9-26
12. Пример 12-3
13. Пример 9-12
14. Пример 33-11
15. Пример 10-8
Это все, что я хотел рассказать об awk. Дополнительные ссылки на информацию об awk, вы найдете в разделе Литература.
Приложение C. Коды завершения, имеющие предопределенный смысл
Таблица C-1. "Зарезервированные" коды завершения
Код завершения Смысл Пример Примечание 1 разнообразные ошибки let "var1 = 1/0" различные ошибки, такие как "деление на ноль" и пр. 2 согласно документации к Bash -- неверное использование встроенных команд Встречаются довольно редко, обычно код завершения возвращается равным 1 126 вызываемая команда не может быть выполнена возникает из-за проблем с правами доступа или когда вызван на исполнение неисполняемый файл 127 "команда не найдена" Проблема связана либо с переменной окружения $PATH, либо с неверным написанием имени команды 128 неверный аргумент команды exit exit 3.14159 команда exit может принимать только целочисленные значения, в диапазоне 0 - 255 128+n фатальная ошибка по сигналу "n" kill -9 $PPID сценария $? вернет 137 (128 + 9) 130 завершение по Control-C Control-C -- это выход по сигналу 2, (130 = 128 + 2, см. выше) 255* код завершения вне допустимого диапазона exit -1 exit может принимать только целочисленные значения, в диапазоне 0 - 255Согласно этой таблице, коды завершения 1 - 2, 126 - 165 и 255[ 67 ] имеют предопределенное значение, поэтому вам следует избегать употребления этих кодов для своих нужд. Завершение сценария с кодом возврата exit 127, может привести в замешательство при поиске ошибок в сценарии (действительно ли он означает ошибку "команда не найдена"? Или это предусмотренный программистом код завершения?). В большинстве случаев, программисты вставляют exit 1, в качестве реакции на ошибку. Так как код завершения 1 подразумевает целый "букет" ошибок, то в данном случае трудно говорить о какой либо двусмысленности, хотя и об информативности -- тоже.
Не раз предпринимались попытки систематизировать коды завершения (см. /usr/include/sysexits.h), но эта систематизация предназначена для программистов, пишущих на языках C и C++. Автор документа предлагает ограничить коды завершения, определяемые пользователем, диапазоном 64 - 113 (и, само собой разумеется -- 0, для обозначения успешного завершения), в соответствии со стандартом C/C++. Это сделало бы поиск ошибок более простым.
Все сценарии, прилагаемые к данному документу, приведены в соответствие с этим стандартом, за исключением случаев, когда существуют отменяющие обстоятельства, например в Пример 9-2.
Обращение к переменной $?, из командной строки, после завершения работы сценария, дает результат, в соответствии с таблицей, приведенной выше, но только для Bash или sh. Под управлением csh или tcsh значения могут в некоторых случаях отличаться.
Приложение D. Подробное введение в операции ввода-вывода и перенаправление ввода-вывода
написано 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