Чтение онлайн

ЖАНРЫ

Шрифт:

> echo Привет!
нажатие клавиши <Enter>

> done
 нажатие клавиши <Enter>

После этого вы увидите слово "Привет!", выводимое на экран в бесконечном цикле. (Если вы все-таки воспроизвели этот пример, нажмите клавиши <Ctrl>+<C> или <Del>.)

Переменные, которые определены, являются внутренними переменными командного интерпретатора и не попадают в его окружение автоматически. Таким образом, они не могут быть использованы другими программами, запускаемыми из shell (окружение наследуется порожденными процессами). Для того чтобы поместить необходимые переменные в окружение shell и тем самым сделать их доступными для других приложений, эти переменные должны быть отмечены как экспортируемые. В этом случае при вызове

какой-либо программы они автоматически попадут в ее окружение. Например, программа работы с электронной почтой получает имя файла — почтового ящика через переменную MAIL, программы, работающие с терминалом, например полноэкранный редактор, обращаются к базе данных терминалов, используя переменную TERM. Разработанная вами программа также может получать часть информации через переменные окружения. Для этого она должна использовать соответствующие функции (getenv(3C) и putenv(3C)), которые мы подробнее рассмотрим в следующей главе.

Встроенные переменные

Помимо переменных, определяемых явно, shell имеет ряд внутренних переменных, значения которых устанавливаются самим интерпретатором. Поскольку это внутренние переменные, имя переменной вне контекста получения ее значения не имеет смысла (т.е. не существует переменной #, имеет смысл лишь ее значение $#). Эти переменные приведены в табл. 1.8.

Таблица 1.8. Внутренние переменные shell

$1, $2, ...
Позиционные параметры скрипта
$#
Число позиционных параметров скрипта
$?
Код возврата последнего выполненного процесса
$5
PID текущего shell
$!
PID последнего процесса, запушенного в фоновом режиме
$*
Все параметры, переданные скрипту. Передаются как единое слово, будучи заключенным в кавычки:
"$*" = "$1 $2 $3 ..."
$@
Все параметры, переданные скрипту. Передаются как отдельные слова, будучи заключенным в кавычки:
"$*" = "$1" "$2" "$3 ..."

Эти переменные редко используются при работе в командной строке, основная область их применения — скрипты. Рассмотрим несколько примеров.

Текст скрипта test1.sh:

#!/bin/sh

echo скрипт $0

echo $1 $2 $3

shift

echo $1 $2 $3

Запуск скрипта

$ ./test1.sh a1 a2 a3 a4 a5

скрипт ./test.sh

a1 a2 a3

a2 a3 a4

Переменные $1, $2, ... $9 содержат значения позиционных параметров — аргументов запущенного скрипта. В $1 находится первый аргумент (a1), в $2 — a2 и т.д. до девятого аргумента. При необходимости передать большее число аргументов, требуется использовать команду shift n, производящую сдвиг значений аргументов на n позиций (по умолчанию — на одну позицию). Приведенный скрипт иллюстрирует этот прием. В переменной $0 находится имя запущенного скрипта. Здесь наблюдается полная аналогия с массивом параметров argv[], передаваемом программе на языке С.

Значение $# равно числу позиционных параметров. Его удобно использовать при проверке соответствия числа введенных пользователем параметров требуемому.

Текст скрипта test2.sh:

#!/bin/sh

if [ $# -lt 2 ]

then

 echo usage: $0 arg1 arg2

 exit 1

fi

Запуск скрипта

$ test2.sh

usage: test2.sh arg1 arg2

$ test2.sh h1 h2

$

В данном примере использовано условное выражение if и проверка, которые мы рассмотрим ниже.

Код возврата последней выполненной задачи ($?) удобно использовать в условных выражениях. По правилам успешным завершением задачи считается код возврата, равный 0, ненулевой код возврата свидетельствует об ошибке. Код возврата скриптов генерируется

с помощью команды exit n, где n — код возврата (см. предыдущий пример). В приведенном ниже примере определяется, зарегистрирован ли в системе пользователь с именем "sergey". Для этого программой grep(1) производится поиск слова sergey в файле паролей. В случае удачи grep(1) возвращает 0. Если слово не найдено, то grep(1) возвращает ненулевое значение, в данном случае это свидетельствует, что пользователь с именем sergey в системе не зарегистрирован.

Текст скрипта test3.sh:

#!/bin/sh

grep sergey /etc/passwd

if [ $?
– ne 0 ]

then

 echo пользователь sergey в системе не зарегистрирован

fi

Каждый активный процесс в UNIX имеет уникальный идентификатор процесса, PID. Запуская скрипт, вы порождаете в системе процесс с уникальным PID. Значение PID сохраняется в переменной $$. Эту переменную удобно использовать в названиях временных файлов, поскольку их имена будут уникальными, например:

Текст скрипта test4.sh:

#!/bin/sh

tmpfile=/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. Пример перенаправления стандартных потоков ввода/вывода

Рассмотрим несколько примеров перенаправления потоков.

Запуск некой программы ведения журнала можно выполнить следующим образом:

$ logger >> file.log

При этом вывод программы logger будет записываться в конец файла file.log, сохраняя все предыдущие записи. Если файла file.log не существует, он будет создан. В отличие от этого, использование символа '>' указывает, что сначала следует очистить файл, а затем производить запись.

Стандартным потокам ввода, вывода и вывода ошибок присваиваются дескрипторы — числовые значения, являющиеся указателями на соответствующий поток. Они, соответственно, равны 0, 1 и 2. Перенаправлять потоки можно, используя эти числовые значения. Таким образом, предыдущему примеру эквивалентна следующая запись:

$ logger 1>>file.log

Чаще всего числовое значение дескриптора потока используется для потока ошибок. Например, чтобы подавить вывод ошибок, можно использовать следующую запись:

Поделиться с друзьями: