В рамках этого курса мы будем рассматривать, в основном, средства, не выходящие за
пределы возможностей командных интерпретаторов sh и ksh (в классической
версии 1988 года).
Командные строки рассматриваются по одной и имеют определенную структуру. Чтобы
понять ее, рассмотрим ряд синтаксических определений:
Список в круглых скобках выполняется в порожденном командном интерпретаторе. Круглые скобки
обычно используют для группировки команд.
Список в фигурных скобках выполняется в текущем командном интерпретаторе, без
порождения дополнительного процесса, и замещает образ командного интерпретатора
(это аналог системного вызова exec).
Операторы управления и синтаксис определения функций рассматривается далее.
Ряд символов, как было описано выше, имеют для командного интерпретатора
специальное значение - это метасимволы. Они описаны в табл. 23.
- Примечание
- Большинство метасимволов будет рассматривается по ходу изложения. Здесь мы
остановимся на тех из них, которые используются для генерации имен файлов и
экранирования.
Перед выполнением команды каждое слово-аргумент команды просматривается в поисках
метасимволов *, ? и [. Если в слове есть один из этих символов,
слово рассматривается как шаблон (обратите внимание на синтаксические отличия от
шаблонов ed). Такое слово
заменяется отсортированными в алфавитном порядке именами файлов, соответствующих
шаблону. Если ни одно их имен файлов не соответствует шаблону, слово оставляется без
изменений. Символ . в начале имени файла или сразу после /, а также
сам символ /, должны сопоставляться явно.
При таком количестве метасимволов интерпретатора необходимо иметь возможность
экранировать специальный символ от интерпретации. Для этого можно использовать
апострофы, кавычки или обратную косую. При этом кавычки одного вида могут
экранировать кавычки другого вида. Обратите внимание, что кавычки "", в отличие от
апострофов, не экранируют строку полностью - интерпретатор заглядывает внутрь
кавычек в поисках $, `...` и \.
В кавычках могут содержаться переводы строк, пробелы, табуляции, символы ;,
&, (, ), |, ^, < и >.
Задавая имя файла в кавычках, можно создать файлы с такими нетривиальными
символами в именах. Впрочем, делать это не рекомендуется, так как работать с ними
будет явно неудобно.
Имея последовательность команд, которую придется многократно использовать,
преобразуем ее для удобства в "новую" команду со своим именем и будем использовать ее
как обычную команду. Предположим, что вам как администратору предстоит часто
подсчитывать количество пользователей, работающих в настоящий момент в системе, при
помощи простого конвейера
$ who | wc -l
и для этой цели нужна новая программа nu.
Первым шагом будет создание обычного текстового файла, содержащего текст конвейера.
Можно воспользоваться вашим любимым текстовым редактором, а можно проявить
изобретательность:
$ echo 'who | wc -l' >nu
Интерпретатор является такой же программой, как редактор, who или wc. Раз это
программа, ее можно вызвать и переключить ее входной поток. Итак, запускаем
интерпретатор с входным потоком, поступающим из файла nu, а не с терминала:
$ who
oracle pts000 Aug 20 10:08
root console Aug 20 09:03
intdbi pts004 Aug 20 12:45
$ cat nu
who | wc -l
$ sh < nu
3
$
Результат получился таким же, как и при вводе команды с терминала. Как и многие
другие программы, интерпретатор обрабатывает файл, если он указан в качестве
аргумента; вы с тем же успехом могли бы задать:
$ sh nu
На самом деле, этот вызов отличается, так как входной поток sh остается связанным с
терминалом.
Не хотелось бы вводить sh каждый раз, кроме того, это создает различие между
командами, написанными на языке shell, и другими выполняемыми файлами. Поэтому,
если текстовый файл предназначен для выполнения, то интерпретатор считает, что он
состоит из команд (интерпретатор csh требует, чтобы файл начинался с #).
- Примечание
- Если в первой строке выполняемого текстового файла указано:
#!/полный_путь_к_программе опции_программы
то данный текстовый файл будет интерпретироваться указанной программой, при
вызове которой будут установлены заданные опции. Так можно выполнять,
например, программы командного интерпретатора csh, не выходя из sh. Точно так
же можно автоматически вызвать и интерпретаторы других языков сценариев,
например, Perl.
Все, что вам нужно сделать, это объявить файл nu выполняемым, задав:
$ chmod +x nu
а затем вы можете вызывать его посредством
$ nu
На самом деле, при выполнении команды nu создается новый процесс интерпретатора
(порожденный интерпретатор), который и выполняет команды, содержащиеся в nu. Чтобы
команда выполнялась в том же интерпретаторе, необходимо поставить перед вызовом
команды точку (.). Заметьте, что
$ . nu
выполняется быстрее, чем простой вызов nu.
В большинстве программ надо использовать аргументы - файлы, флаги и т.д. В соответствии с
синтаксисом командной строки, это можно сделать, передавая их после имени команды
через пробелы.
Предположим, необходимо программу cx для установки права доступа к файлу на выполнение,
так что
$ cx nu
есть сокращенная запись для
$ chmod +x nu
Создать такой сценарий не сложно. Остается только один вопрос - как получить в
программе доступ к имени файла-аргумента. Для этого в командном интерпретаторе
используются позиционные параметры.
При выполнении командного файла, каждое вхождение $1 заменяется первым аргументом,
$2 - вторым и так далее до $9. $0 заменяется именем выполняемой команды.
Поэтому, если файл cx содержит строку
chmod +x $1
то при выполнении команды
$ cx nu
порожденный интерпретатор заменит $1 первым аргументом команды nu.
Значения позиционным параметрам присваиваются при вызове сценария, при вызове
функции в сценарии или явно, с помощью команды set.
Как быть, если нужно работать с несколькими аргументами, например, заставить программу
cx делать выполняемыми несколько файлов? Можно включить девять аргументов в
командный файл (явно можно задавать только девять аргументов, так как конструкция
$10 распознается как "первый аргумент, за которым следует 0"):
chmod +x $1 $2 $3 $4 $5 $6 $7 $8 $9
Если пользователь такого командного файла задаст менее девяти аргументов,
то оставшиеся окажутся пустыми строками и только настоящие аргументы будут переданы
chmod порожденным интерпретатором. Но такое решение не подходит,
если количество аргументов превышает девять.
Интерпретатор предоставляет специальный параметр $*, который заменяется
всеми аргументами команды, независимо от их количества. С учетом этого,
правильное определение cx будет таким:
chmod +x $*
Все позиционные и специальные параметры, поддерживаемые командным интерпретатором,
представлены в табл. 24.
Таблица 24. Позиционные и специальные параметры
командного интерпретатора
Параметр |
Назначение |
$0 |
Имя выполняемой команды |
$1,$2,...$9 |
Заменяются аргументами командного файла |
$# |
Количество аргументов |
$* |
Все аргументы, передаваемые интерпретатору. "$*" является единым словом,
образованным из всех аргументов, объединенных вместе с пробелами. |
$@ |
Аналогично $*. "$@" идентично аргументам: пробелы в аргументах
игнорируются, и получается список слов, идентичных исходным аргументам. |
$- |
Флаги, установленные в интерпретаторе. |
$? |
Значение, возвращенное последней выполненной командой (статус выхода). |
$$ |
Номер процесса интерпретатора. |
$! |
Номер процесса последней команды, запущенной асинхронно с помощью &. |
Подобно большинству языков программирования, командный интерпретатор имеет переменные,
которые называют еще ключевыми параметрами (поскольку они предаются
по имени - ключу).
Переменные можно создавать, изменять и выбирать их значения. Для присваивания
значения переменной применяется конструкция:
переменная=значение
Обратите внимание на отсутствие пробелов до и после знака присваивания. Вспомните,
что командный интерпретатор считает пробелы разделителями слов. Если поставить
пробел после знака присваивания, то интерпретатор не изменит значения переменной,
но будет искать команду с именем значение.
Присваиваемое значение должно выражаться одним словом, и его следует взять в кавычки,
если оно содержит метасимволы, которые не нужно обрабатывать.
Создание (определение) переменной происходит при первом присваивании ей значения.
Переменные не нужно явно объявлять до момента их использования. Если переменная не объявлена
(не получила значения), при обращении к ней будет получена пустая строка. Все переменные в
командном интерпретаторе - строковые, поэтому тип переменной задавать не надо.
Некоторые команды интерпретируют строки как числа.
Многие переменные, как, например, PATH, имеют специальное значение для интерпретатора.
По традиции, такие переменные называют встроенными и обозначают прописными
буквами, а обычные переменные - строчными. Основные встроенные переменные
представлены в табл. 25.
Таблица 25. Встроенные переменные командного интерпретатора
Переменная |
Значение |
$HOME |
Начальный каталог пользователя. |
$PATH |
Путь для поиска выполняемых команд. |
$CDPATH |
Путь поиска для команды cd. |
$IFS |
Список символов, разделяющих слова в аргументах |
$MAIL |
Файл почтового ящика. Командный интерпретатор информирует пользователя
о получении почты в указанный файл. |
$MAILCHECK |
Эта переменная определяет, как часто (в секундах) интерпретатор будет
проверять поступление почты в файл, определяемый переменной MAIL. По
умолчанию принято значение 600 секунд. При установке в 0, интерпретатор
будет проверять почту перед каждой выдачей строки-приглашения. |
$PS1 |
Строка-приглашение, по умолчанию принята '$ ' |
$PS2 |
Строка-приглашение при продолжении командной строки, по умолчанию
принята '> ' |
Типичным примером использования переменных является хранение в них длинных строк,
таких как имена файлов:
$ pwd
/home/intdbi/dosapps/doc/book/unix/shell
$ dir=`pwd`
$ cd
$ ln $dir/cx .
...
$ cd $dir
$ pwd
/home/intdbi/dosapps/doc/book/unix/shell
Встроенная команда интерпретатора set, при вызове без параметров показывает значение всех
определенных переменных.
Переменные называют ключевыми параметрами, поскольку им можно передавать значение
по имени при вызове. Рассмотрим пример:
$ echo 'echo $x' >echox
$ cx echox
$ echo $x
Hello
$ echox
$ x=Hi echox
Hi
По умолчанию ключевые параметры можно передавать только до имени команды. Если установить флаг
интерпретатора -k (set -k), то можно будет передавать значения переменным и
после имени команды.
Каждый экземпляр командного интерпретатора имеет свой набор переменных, размещаемых в отдельной
области памяти. Если необходимо, чтобы определенная переменная в порожденных процессах имела
конкретное значение, необходимо экспортировать ее в среду. Такая переменная
называется переменной среды.
Для всех экспортированных переменных при запуске порожденного процесса создаются их локальные
копии с теми же значениями. Рассмотрим пример:
$ x=Hello
$ export x
$ PS1='new$ ' sh
new$ echo $x
Hello
new$ x='Good Bye'
new$ echo $x
Good Bye
new$ exit
$
$ echo $x
Hello$
Изменение значение переменной в порожденном интерпретаторе не влияет на ее значение
в родительском интерпретаторе.
Для просмотра значений всех переменных среды предназначена команда env.
Командный интерпретатор поддерживает циклическую обработку. Чаще всего на практике
используется цикл for - цикл по списку слов. Он описан в следующем подразделе.
Обратите внимание, что выделенные полужирным ключевые слова должны быть первым
словом команды, т.е. первым словом в строке или идти сразу после точки с запятой.
Цикл for имеет следующий синтаксис:
- <цикл for> ::=
-
for <имя переменной> [in <список слов>] do <команды> done
- <список слов> ::=
- <слово>{<пробел> <слово>}
- <команды> ::=
- <команда> {<; или перевод строки> <команда>}
Переменная последовательно получает значение очередного слова из списка, и для этого значения
выполняются команды в теле цикла. Цикл завершается, когда пройден весь список слов. По умолчанию в
качестве списка слов используются аргументы командной строки.
Рассмотрим пару примеров таких циклов:
$ for i in 1 2 3 4 5
> do
> echo $i
> done
Обратите внимание, что командный интерпретатор распознает цикл, выдает вторичное приглашение,
и выполняет цикл только после его завершения ключевым словом done.
Список слов для цикла обычно порождается динамически. Например, путем раскрытия шаблонов имен
файлов:
$ for i in *.c *.h
> do
> echo $i
> diff -b old/$i $i
> echo
> done | pr -h "diff `pwd`/old `pwd`" | lp &
[4] 1430
Можно также порождать его командой, подставляя ее результаты:
$ for i in `pick *.c *.h`
> do
> echo $i:
> diff -b old/$i $i
> done | pr | lp
Командный интерпретатор поддерживает также традиционные циклы по условию со следующим
синтаксисом:
- <оператор while> ::=
- while <команды> do <команды> done
- <оператор until> ::=
- until <команды> do <команды> done
Выполняются команды, задающие условие, и проверяется код возврата последней из них.
Если это ноль (истина), выполняются команды в теле цикла while или
завершается выполнение цикла until. Если это не ноль (ложь),
завершается работа цикла while или выполняется очередная итерация цикла until.
На основе этих циклов часто создаются программы-"следилки", работающие бесконечно:
$ cat watchfor
# watchfor: watching for log ins and log outs...
PATH=/usr/bin
new=/tmp/wfor1.$$
old=/tmp/wfor2.$$
>$old # создает пустой файл
while : # бесконечный цикл
do
who >$new
diff $old $new
mv $new $old
sleep 60
done | awk ' />/ { $1 = "in: "; print }
/</ { $1 = "out: "; print }'
$
Командный интерпретатор поддерживает выполнение того или иного блока команд в зависимости от
значения некоторого слова. Для этого предлагается оператор case
со следующим синтаксисом:
- <оператор выбора> ::=
- case <слово> in
<описание варианта> ) <команды> ;;
{<описание варианта> ) <команды> ;; }
esac
- <описание варианта> ::=
- <шаблон> { | <шаблон>}
- <команды> ::=
- <команда> {<разделитель> <команда>}
- <разделитель> ::=
- <перевод строки> | ;
Слово (обычно - значение переменной) сравнивается последовательно с шаблонами. Если произошло
сопоставление (по правилам сопоставления шаблонов имен файлов) выполняются команды,
соответствующие данному варианту и оператор завершается. Учтите, что шаблон *)
сопоставляется с любым словом, и, тем самым, задает вариант по умолчанию.
В шаблонах оператора case символы . и /, в отличие от шаблонов
имен файлов, не обязательно задавать явно.
Командный интерпретатор поддерживает условный оператор следующего общего вида:
- <условный оператор> ::=
- if <команды> then <команды>
{elif <команды> then <команды>}
[else <команды>]
fi
Выполняются команды после if и проверяется код возврата последней из них.
Если это 0 (истина) выполняются соответствующие команды после then
и выполнение оператора завершается. Если же это не 0 (ложь),
то при наличии конструкций elif выполняются последовательно соответствующие
команды-условия и, если они возвращают код 0, команды после then, а затем оператор
завершается. Если ни одно из условий не было истинным, выполняются команды в
части else и оператор завершается.
В качестве условия в условном операторе может использоваться любая команда. Однако, имеется
стандартная команда для проверки условий в традиционном понимании.
Это команда test, представленная в следующем разделе.
Команда test имеет следующий синтаксис:
- <команда test> ::=
- test <выражение> | [ <выражение> ]
Выражение строится из примитивов, представленных в табл. 26,
при необходимости, с помощью следующих операторов:
! |
Унарный оператор отрицания. |
-a |
Бинарный оператор "и". |
-o |
Бинарный оператор "или". |
(<выражение>) |
Скобки для группировки. Учтите, что скобки распознаются командным
интерпретатором, поэтому их надо брать в кавычки. |
Таблица 26. Основные примитивы команды test
Примитив |
Условие |
-r файл |
файл существует и доступен для чтения |
-w файл |
файл существует и доступен для записи |
-x файл |
файл существует и является выполняемым |
-f файл |
истина, если файл существует и является обычным файлом (не каталогом) |
-d файл |
файл существует и является каталогом |
-h файл |
файл существует и является символьной связью |
-s файл |
файл существует и не пуст |
-t [ дескриптор ] |
истина, если открытый файл с указанным дескриптором (по умолчанию, 1)
ассоциирован с терминалом |
-z s1 |
истина, если строка s1 имеет нулевую длину |
-n s1 |
истина, если строка s1 имеет ненулевую длину |
s1 = s2 |
истина, если строки s1 и s2 идентичны |
s1 != s2 |
истина, если строки s1 и s2 не совпадают |
s1 |
истина, если строка s1 непустая |
n1 -eq n2 |
сравнение целых чисел на равенство (=). Можно использовать также и другие
сравнения: -ne (!=), -gt (>), -ge (>=),
-lt (<) и -le (<=). |
Рассмотрим пример использования условного оператора и команды test:
$ cat which
# which cmd: Безопасная версия сценария для выдачи каталога,
# из которого будет вызываться выполняемая программа
opath=$PATH
PATH=/usr/bin
# Это гарантирует использование настоящих команд
# echo, sed и test в любом случае!
case $# in
0) echo 'Usage: which command' 1>&2; exit 2
esac
for i in `echo $opath | sed 's/^:/.:/
s/::/:.:/g
s/:$/:./
s/:/ /g'`
do
if test -x $i/$1
then
echo $i/$1
exit 0 # команда найдена
fi
done
exit 1 # не найдена
$ which sed
./sed
$ which which
./which
В программах командного интерпретатора можно перехватывать и обрабатывать сигналы. Для этого
используется команда trap, устанавливающая с момента выполнения обработчик в виде
последовательности команд (одним словом) для всех перечисленных сигналов.
Эта команда имеет следующий синтаксис:
- <оператор trap> ::=
- trap <последовательность команд> <список сигналов>
- <список сигналов> ::=
- <сигнал> {<пробелы> <сигнал>}
Рассмотрим пример реализации команды nohup, позволяющей запустить программу так,
чтобы она продолжала работать при выключении терминала:
$ cat nohup
# nohup: no kill and hangup
trap "" 1 15
if test -t 2>&1
then
echo "Redirect stdout to 'nohup.out'"
exec nice -5 $* >>nohup.out 2>&1
else
exec nice -5 $* 2>&1
fi
$
Командный интерпретатор позволяет, при необходимости, запрашивать у пользователя информацию,
которая помещается в указанную переменную. Для этого используется команда read:
$ read greeting
Hello, world!
$ echo $greeting
Hello, world!
$
На практике имеет смысл перед запросом выдать приглашение с помощью команды echo.
Например, вот так:
$ cat pick
# pick: select arguments
PATH=/bin:/usr/bin
for i # for each argument, try $*, "$*" and "$@"
do
echo -n "$i? " > /dev/tty
read responce
case $responce in
y*) echo $i;;
q*) break
esac
done </dev/tty
$
Представленная выше программа pick выдает каждое указанное в качестве аргумента
слово в отельной строке со знаком вопроса и требует от пользователя подтвердить необходимость
его выдачи в стандартный выходной поток. Поскольку эта программа может использоваться
в других сценариях, входной и выходной потоки которых перенаправлены, она взаимодействует
непосредственно с текущим терминалом (через устройство /dev/tty).
Вычисления можно выполнять с помощью любой программы, воспринимающей свои параметры как
выражение, значение которого необходимо вычислить, и выдающей результат вычисления в стандартный
выходной поток. Одна из таких программ, expr, рассмотрена далее. Но современные командные
интерпретаторы включают встроенную команду для выполнения простейших арифметических действий.
Это команда let:
- <команда let> ::=
- let <аргумент> {<аргумент>}
Вот как ее можно использовать:
$ let a=5
$ echo $a
5
$ let a=a*a+34/2
$ echo $a
42
$ let "a = 7"
$ echo $a
7
Обратите внимание, что если вокруг знака равенства идут пробелы, необходимо брать выражение в
кавычки. Команда let требует, чтобы выражение было одним словом. Кроме того,
для обращения к значению переменной в этой команде не нужно использовать
метасимвол $.
Одной из стандартных программ-калькуляторов является программа expr.
Ее основные операторы представлены в табл. 27.
Таблица 27. Основные операторы, распознаваемые командой expr
Оператор |
Результат |
выр1 \| выр2 |
Возвращает значение первого выражения, если оно не пустое и не равно
0, иначе, возвращает значение второго выражения. |
выр1 \& выр2 |
Возвращает значение первого выражения, если оба выражения - не
пустые и не равны 0, иначе, возвращает 0. |
выр1 { +, - } выр2 |
Складывает или вычитает целочисленные аргументы. |
выр1 { \*, /, % } выр2 |
Умножает, делит или возвращает остаток от деления для целочисленных
аргументов. |
length строка |
Возвращает длину строки. |
Рассмотрим простой пример вычисления с помощью expr:
$ a=5
$ echo $a
5
$ a=`expr $a \* $a + 34 / 2`
$ echo $a
42
Обратите внимание, что между элементами выражения надо указывать пробелы.
Стандартным способом разбиения программ на модули в командном интерпретаторе
является оформление необходимых действий в виде отдельного выполняемого файла с программой
командного интерпретатора - создание новой команды. Тем не менее, для некоторых модулей
такой подход может оказаться неэффективным и избыточным, так как модули могут не представлять
самостоятельного значения вне программы, в которой они используются. Поэтому в современных
версиях командных интерпретаторов предлагается возможность создавать и вызывать функции.
Синтаксис определения функции
Для определения функций используется ключевое слово function. Функции читаются
и хранятся внутренне командным интерпретатором. Функции выполняются как команды,
причем аргументы передаются как позиционные параметры. Синтаксис определения функции
следующий:
- <определение функции> ::=
- function <идентификатор> { <список команд> } |
<идентификатор> () { <список команд> }
где список команд задает команды, выполняемые в качестве тела функции.
Команды обычно разделяются точкой с запятой или переводами строк.
Выполнение и использование функций
Функции выполняются вызвавшим их процессом и используют все его файлы и текущий рабочий
каталог. Сигналы, перехватываемые вызывающим процессом, внутри фунции обрабатываются стандартным
образом. Сигналы, не перехватываемые или игнорируемые функцией, прекращают ее выполнение и
передаются вызвавшей команде.
Обычно переменные совместно используются вызывающей программой и функцией. Однако, специальная
команда typeset, используемая внутри функции, позволяет
определять локальные переменные, область действия которых - текущая функция
и все вызываемые ею функции.
Для выхода из функции используется специальная команда return. В случае ошибки в
функции, управление передается вызывающей команде.
Идентификаторы определенных функций можно получить с помощью опций -f или +f
специальной команды typeset. Текст функций показывается при использовании опции -f.
Определение функции можно отменить с помощью опции -f специальной
команды unset.
Обычно при выполнении сценария командным интерпретатором никакие функции не заданы.
Опция -xf команды typeset позволяет экспортировать функцию для использования
сценариями, выполняемыми без отдельного вызова интерпретатора. Функции, которые должны быть
определены для всех вызовов интерпретатора, необходимо задавать в файле начального запуска с
помощью опций -xf команды typeset.
Рассмотрим классический пример итеративной реализации функции вычисления факториала:
# test.sh - test shell functions
factorial () {
typeset i
typeset n
i=1; n=1
while [ $i -le $1 ]
do
let n=n*i
let i=i+1
done
echo $n
return
}
a=`factorial $11`
echo $a
При вызове эта программа, как и ожидалось, вычислит факториал своего первого параметра:
bash$ test.sh 5
120
Часто в виде функций оформляется выдача сообщений о параметрах вызова программы.
В любом случае, если задача может быть разбита на подзадачи, решение этих подзадач имеет
смысл оформлять в виде отдельной команды, если они полезны не только в контексте
решаемой задачи, или в виде функции в противном случае.
Стандартная среда для работы командных интерпретаторов задается в
файлах начального запуска, которые автоматически выполняются в начальном интерпретаторе
с помощью команды точка (.), т.е. без порождения. Файлы начального запуска размещаются в
начальном каталоге пользователя и называются .profile (sh, ksh)
или .bash_profile (bash). Переменные, составляющие среду, в файле
начального запуска надо экспортировать.
Рассмотрим пример содержимого файла начального запуска:
INFORMIXDIR=/usr/inf.731
INFORMIXSERVER=onarturo7
ONCONFIG=onconfig
SQLHOSTS=sqlhosts
PATH=$PATH:$INFORMIXDIR/bin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$INFORMIXDIR/lib/esql:$INFORMIXDIR/lib
DB_LOCALE=ru_ru.8859-5
CLIENT_LOCALE=ru_ru.8859-5
KAIOON=1
NODEFDAC=YES
DBDATE=DMY4/
DBTIME='%H:%M:%S %d/%m/%Y'
DBMONEY=.4
export KAIOON
export INFORMIXDIR INFORMIXSERVER LANG PATH ONCONFIG SQLHOSTS
export DBDATE DBTIME DBMONEY NODEFDAC
export DB_LOCALE CLIENT_LOCALE
Управление заданиями - это механизм для отслеживания процессов, которые порождаются
из текущего сеанса работы с терминалом. Можно запустить любое число заданий. Они могут работать,
завершиться или находиться в других состояниях. Для управления заданиями можно использовать
несколько команд, чтобы проследить результаты их работы или потребовать от системы уведомления
об окончании задания.
Фоновый режим позволяет продолжить использование сеанса работы с терминалом, пока выполняется
команда. Для запуска команды в фоновом режиме, достаточно к команде добавить символ
амперсанд (&). Командный интерпретатор вернет номер задания и идентификатор процесса:
$ make &
[2] 254
$
Если задание не требует от пользователя ввода, оно продолжает свою работу до полного
завершения. Если команде нужен ввод, она переходит в состояние ожидания, на экран выводится
соответствующее уведомление, которое выглядит примерно так:
[1] + Suspended (tty input) programm 0
В данном случае в ожидании ввода приостановилось выполнение программы programm.
Пользователю необходимо перевести из фонового режима в привилегированный и выполнить ввод.
С помощью команды jobs пользователь имеет возможность просмотреть состояние
своих заданий и получит список всех заданий запущенных в сеансе работы с терминалом.
$ jobs
[1] Stopped (user) du
[2]- Stopped (user) du -a /home/intdbi
[3]+ Stopped (user) du -r /home/intdbi
$
Команда jobs принимает два флага. Флаг -l включает идентификатор процесса с
номером задания.
$ jobs -l
[1] 1351 Stopped (user) du
[2]- 1381 Stopped (user) du -a /home/intdbi
[3]+ 1383 Stopped (user) du -r /home/intdbi
$
Флаг -р заменяет номер задания на идентификатор процесса.
$ jobs -p
1351
1381
1383
$
Идентификатор процесса может использоваться при обращении к команде ps.
Номера заданий
Номер задания позволяет командному интерпретатору наблюдать за процессами.
Его можно рассматривать как головной элемент группы процессов, поскольку пользовательское
задание порождает любые команды либо в конвейере, либо, как подзадания.
Команда fg переводит задания в привилегированный режим. При наличии
приостановленного задания, его можно сделать привилегированным (перевести на передний план)
с помощью команды fg #номер_задания (или fg номер_задания в bash).
После этого задание либо выведет на экран сообщение о том, что ему нужно
от терминала, либо будет принимать ожидаемый ввод. Переведя задание в привилегированный режим,
можно приостановить его выполнение, нажав комбинацию калвиш Ctrl-Z, и заняться им позже.
Любое задание из списка, предоставленного командой jobs, доступно,
если пользователь захочет сделать его привилегированным, даже в том случае,
когда оно уже работает в фоновом режиме. Если в этом списке
приведено только одно задание, то при использовании команды fg пользователю
не нужно задавать его номер. Если номер задания не задан, предполагается текущее задание.
С помощью команды bg можно возобновить в фоновом режиме работу приостановленного или
остановленного задания. Для этого нужно указать соответствующий номер задания, после чего оно
перейдет в фоновый режим, и будет работать до своего завершения, или пока ему снова
не потребуется ввод с терминала.
Это последняя существенная команда управления заданиями. При вводе wait
приостанавливается работа командного интерпретатора до тех пор, пока не будут завершены
все фоновые задания. Сюда входят и любые остановленные задания, поэтому при вводе wait
стоит убедиться, что все фоновые задания работают. Команда wait может также принимать
в качестве параметра номер задания. В этом случае командный
интерпретатор приостанавливается до тех пор, пока не завершится выполнение указанного задания.
Назад Оглавление Вперёд