Операционная система UNIX
Текст скрипта test4.sh:
#!/bin/shtmpfile=/usr/tmp/tmp.$$...rm $tempfileПеренаправление ввода/вывода
Каждая запущенная из командного интерпретатора программа получает три открытых потока ввода/вывода:
□ стандартный ввод
□ стандартный вывод
□ стандартный вывод ошибок
По умолчанию все эти потоки ассоциированы с терминалом. То есть любая программа, не использующая потоки, кроме стандартных, будет ожидать ввода с клавиатуры терминала, весь вывод этой программы, включая сообщения об ошибках, будет происходить на экран терминала. Большое число утилит, с которыми вам предстоит работать, используют только стандартные потоки. Для таких программ shell позволяет независимо перенаправлять потоки ввода/вывода. Например, можно подавить вывод сообщений об ошибках, установить ввод или вывод из файла и даже передать вывод одной программы на ввод другой.
В табл. 1.9 приведен синтаксис перенаправления ввода/вывода, а на рис. 1.9 схематически показаны примеры перенаправления потоков.
Таблица 1.9. Перенаправление потоков ввода/вывода
>file Перенаправление стандартного потока вывода в файл file >>file Добавление в файл file данных из стандартного потока вывода <file Получение стандартного потока ввода из файла file p1 | p2 Передача стандартного потока вывода программы p1 в поток ввода p2 n>file Переключение потока вывода из файла с дескриптором n в файл file n>>file To же, но записи добавляются в файл file n>&m Слияние потоков с дескрипторами n и m <<str "Ввод здесь": используется стандартный поток ввода до подстроки str. При этом выполняются подстановки метасимволов командного интерпретатора <<\str To же, но подстановки не выполняются Рис. 1.9. Пример перенаправления стандартных потоков ввода/вывода
Рассмотрим несколько примеров перенаправления потоков.
Запуск некой программы ведения журнала можно выполнить следующим образом:
$ <b>logger >> file.log</b>При этом вывод программы logger будет записываться в конец файла file.log, сохраняя все предыдущие записи. Если файла file.log не существует, он будет создан. В отличие от этого, использование символа '>' указывает, что сначала следует очистить файл, а затем производить запись.
Стандартным потокам ввода, вывода и вывода ошибок присваиваются дескрипторы — числовые значения, являющиеся указателями на соответствующий поток. Они, соответственно, равны 0, 1 и 2. Перенаправлять потоки можно, используя эти числовые значения. Таким образом, предыдущему примеру эквивалентна следующая запись:
$ <b>logger 1>>file.log</b>Чаще всего числовое значение дескриптора потока используется для потока ошибок. Например, чтобы подавить вывод ошибок, можно использовать следующую запись:
$ <b>run 2>/dev/null</b>где /dev/null является псевдоустройством, удаляющим все введенные в него символы.
Командный интерпретатор предоставляет возможность слияния потоков. Например, при запуске команды
$ <b>run_long_program >/dev/null 2>&1 &</b>сообщения об ошибках будут также выводиться в файл /dev/null. Символ '&' перед именем потока необходим, чтобы отличить его от файла с именем 1. Заметим, что изменение порядка двух перенаправлений потоков приведет к тому, что сообщения об ошибках будут по-прежнему выводиться на экран. Дело в том, что Shell анализирует командную строку слева направо, таким образом сначала будет осуществлено слияние потоков и оба будут указывать на терминал пользователя, а затем стандартный поток вывода (1) будет перенаправлен в файл /dev/null.
Передача потока вывода одной программы в поток ввода другой осуществляется с помощью конвейера '|' (программного канала). Программные каналы часто используются для фильтрации вывода некоторой команды:
$ <b>ps - ef | grep myproc</b>позволяет получить информацию о конкретном процессе myproc. Утилита ps(1) выводит на экран информацию обо всех процессах в системе, программа grep(1) фильтрует этот поток, оставляя лишь строки, в которых присутствует слово myproc. [14]
Можно усложнить задачу и попытаться получить идентификатор процесса myproc. Однако здесь нам не обойтись без других средств системы. В данном случае мы будем использовать интерпретатор awk(1):
$ <b>ps -ef | grep myproc | awk '{ print $2 }'</b>Идея заключается в фильтрации второго поля записи о процессе myproc, содержащего идентификатор процесса (см. описание утилиты ps(1)).
Иногда возникает необходимость разместить поток ввода вместе с командой. Для этого используется выражение "ввод здесь". Проиллюстрируем его на примере:
$ <b>at Dec 31 <<!</b><b>cat happy.new.year | elm -s"C Новым Годом"</b><b> [email protected]</b><b>!</b>По определению, команда at(1) устанавливает вызов команды, полученной ею со стандартного ввода (клавиатуры терминала), на определенное время (в данном случае — на 31 декабря каждого года). С помощью выражения "ввод здесь" мы явно задали вид этой команды, точнее комплекса команд: cat(1) передает текст поздравления программе elm(1), отвечающей за отправление сообщения электронной почты.
Команды, функции и программы
Все команды, которые вводятся в строке приглашения shell, относятся к одной из следующих категорий:
□ встроенные функции
□ функции shell, определенные пользователем
□ внешние программы и утилиты
Непосредственное отношение к shell имеют только первые две категории, а программы и утилиты являются обычными исполняемыми файлами.
Запуск встроенной функции не требует порождения нового процесса, поскольку эта функция реализована в самой программе shell (например, /bin/sh). Соответственно, встроенные функции shell выполняются быстрее всего. Рассмотрим важнейшие встроенные функции shell.
:Пустая команда. Код возврата всегда 0 (успех). Пустая команда удобна для создания бесконечных циклов, например: while : do ... done. runmeТекущий командный интерпретатор выполняет команды, указанные в файле runme. При этом не происходит порождения нового shell, как в случае запуска на выполнение runme. Например, использование в скрипте команды выполнит команды файла include_script, как если бы они являлись частью текущего скрипта.. /usr/bin/include_scriptbreak [<i>n</i>]Производит выход из цикла или<i>for</i>. Если параметр<i>while</i>указан, происходит выход из n вложенных циклов<i>n</i>ps -ef | awk '{ print $1 " " $2}' | while read uid pid do if [$pid -eq $PID] then echo pid=$pid user=$uid break fi donecd [dir]Осуществляет переход в каталог . Если параметр не указан, происходит переход в домашний каталог ($HOME)<i><b>dir</b></i>echo [string]Строка выводится на стандартное устройство вывода (терминал)<i>string</i>exec runmeВыполняет программу , заменяя ею текущий командный интерпретатор. Например, если в login shell (командном интерпретаторе, запускаемом при регистрации пользователя в системе) мы вызовем exec ls, то после вывода имен файлов текущего каталога произойдет завершение работы в системе<i>runme</i>exit [<i>n</i>]Завершает работу текущего интерпретатора (или скрипта) с кодом возврата . По умолчанию код возврат равен 0<i>n</i>export [name1], [name2...]Помещает переменные, указанные в качестве аргументов, в окружение текущего shell, делая их тем самым экспортируемыми, т.е. доступными для запускаемых из интерпретатора программ hash [-r] [<i>command</i>, <i>command</i>...]Для каждой команды, указанной в качестве аргумента, запоминается полный путь. Таким образом, при последующих вызовах этих команд поиск не производится. Ключ удаляет все ранее запомненные пути. Если команда hash вызвана без аргументов, то выводится информация о запомненных путях-rjobsЕсли командный интерпретатор поддерживает управление заданиями, данная команда выводит список текущих заданий. См. раздел «Система управления заданиями», далее в этой главе kill [-<i>sig</i>] <i>pid1 pid2</i>...Посылает сигнал, определённый параметром sig, процессам, указанным параметрами . Параметр<i>pid</i>может быть либо идентификатором процесса, либо идентификатором задания, если поддерживается управление заданиями (в этом случае идентификатор должен предваряться символом '%' в соответствии синтаксисом системы управления заданиями). См. раздел «Система управления заданиями далее в этой главе<i>pid</i>pwdВыводит имя текущего каталога read <i>var1 var2</i> ...Построчно считывает слова (т.е. группы символов, разделённые пробелами) из стандартного потока ввода, последовательно присваивая переменным , указанным в качестве параметров значения, равные считанным словам. Если число слов в строке превышает число переменных, то последней переменной присваивается значение, равное остатку строки<i>var</i>return [<i>n</i>]Осуществляет выход из функции с кодом возврата . По умолчанию возвращается код последней команды<i>n</i>setПри задании без параметров выводит список определённых переменных shift [<i>n</i>]Производит сдвиг позиционных параметров, хранящихся в $1, $2 и т.д. на позиций. По умолчанию сдвиг производится на одну позицию<i>n</i>testВычисляет условное выражение. Возвращает значение 0 — истина, или 1 — ложно. См раздел условные выражения далее в этой главе timesВыводит суммарное время использования процессора программами, запущенными из текущего командного интерпретатора trap <i>command sig1 sig2</i> ...Определяет команду , которая будет выполнена при получении сигналов, указанных в качестве аргументов<i>command</i>. См. раздел "Сигналы" ранее в этой главе<i>sig</i>type <i>name</i>Показывает, как будет интерпретироваться командным интерпретатором<i>name</i>ulimitВыводит или устанавливает значение пределов, ограничивающих использование задачей системных ресурсов (времени процессора, памяти, дискового пространства). Ограничения будут рассматриваться в главе 2 umask <i>nnn</i>Устанавливает маску прав доступа для вновь создаваемых файлов равной <i>nnn</i>unset var1 var2 ...Удаляет переменные, указанные в качестве аргументов, из списка определенных переменных командного интерпретатора. Некоторые переменные, например PATH, PS1, PS2, не могут быть удалены wait <i>pid</i>Ожидает завершения выполнения процесса с идентификатором и возвращает его код возврата<i>pid</i>
