| Если сценарий завершается командой exit без аргументов, то в качестве кода завершения сценария принимается код завершения последней выполненной команды, не считая самой команды exit. |
exec
Это встроенная команда интерпретатора shell, заменяет текущий процесс новым процессом, запускаемым командой exec. Обычно, когда командный интерпретатор встречает эту команду, то он порождает дочерний процесс, чтобы исполнить команду. При использовании встроенной команды exec, оболочка не порождает еще один процесс, а заменяет текущий процесс другим. Для сценария это означает его завершение сразу после исполнения команды exec. По этой причине, если вам встретится exec в сценарии, то, скорее всего это будет последняя команда в сценарии.
Пример 11-21. Команда exec
#!/bin/bash
exec echo "Завершение \"$0\"." # Это завершение работы сценария.
# -
# Следующие ниже строки никогда не будут исполнены
echo "Эта строка никогда не будет выведена на экран."
exit 99 # Сценарий завершит работу не здесь.
# Проверьте код завершения сценария
#+ командой 'echo $?'.
# Он точно не будет равен 99.
Пример 11-22. Сценарий, который запускает себя самого
#!/bin/bash
# self-exec. sh
echo
echo "Эта строка в сценарии единственная, но она продолжает выводиться раз за разом."
echo "PID остался равным $$."
# Демонстрация того, что команда exec не порождает дочерний процесс.
echo "==================== Для завершения - нажмите Ctl-C ===================="
sleep 1
exec $0 # Запуск очередного экземпляра этого же сценария
#+ который замещает предыдущий.
echo "Эта строка никогда не будет выведена!" # Почему?
exit 0
Команда exec так же может использоваться для перенаправления. Так, команда exec <zzz-file заменит стандартное устройство ввода (stdin) файлом zzz-file (см. Пример 16-1).
| Ключ - exec команды find -- это не то же самое, что встроенная команда exec. |
shopt
Эта команда позволяет изменять ключи (опции) оболочки на лету (см. Пример 23-1 и Пример 23-2). Ее часто можно встретить в стартовых файлах, но может использоваться и в обычных сценариях. Требует Bash версии 2 или выше.
shopt - s cdspell
# Исправляет незначительные орфографические ошибки в именах каталогов в команде 'cd'
cd /hpme # Oops! Имелось ввиду '/home'.
pwd # /home
# Shell исправил опечатку.
Команды
true
Команда возвращает код завершения -- ноль, или успешное завершение, и ничего больше.
# Бесконечный цикл
while true # вместо ":"
do
operation-1
operation-2
...
operation-n
# Следует предусмотреть способ завершения цикла иначе сценарий "зависнет".
done
false
Возвращает код завершения, свидетельствующий о неудаче, и ничего более.
# Цикл, который никогда не будет исполнен
while false
do
# Следующий код не будет исполнен никогда.
operation-1
operation-2
...
operation-n
done
type [cmd]
Очень похожа на внешнюю команду which, type cmd выводит полный путь к "cmd". В отличие от which, type является внутренней командой Bash. С опцией - a не только различает ключевые слова и внутренние команды, но и определяет местоположение внешних команд с именами, идентичными внутренним.
bash$
type '['
[ is a shell builtin
bash$
type - a '['
[ is a shell builtin
[ is /usr/bin/[
hash [cmds]
Запоминает путь к заданной команде (в хэш-таблице командной оболочки), благодаря чему, при повторном обращении к ней, оболочка или сценарий уже не будет искать путь к команде в $PATH. При вызове команды hash без аргументов, просто выводит содержимое хэш-таблицы. С ключом - r -- очищает хэш-таблицу.
help
help COMMAND -- выводит краткую справку по использованию внутренней команды COMMAND. Аналог команды whatis, только для внутренних команд.
bash$
help exit
exit: exit [n]
Exit the shell with a status of N. If N is omitted, the exit status
is that of the last command executed.
11.1. Команды управления заданиями
Некоторые из нижеследующих команд принимают, в качестве аргумента, "идентификатор задания". См. таблицу в конце главы.
jobs
Выводит список заданий, исполняющихся в фоне. Команда ps более информативна.
| Задания и процессы легко спутать. Некоторые внутренние команды, такие как kill, disown и wait принимают в качестве параметра либо номер задания, либо номер процесса. Команды fg, bg и jobs принимают только номер задания. bash$ sleep 100 & [1] 1384 bash $ jobs [1]+ Running sleep 100 & "1" -- это номер задания (управление заданиями осуществляет текущий командный интерпретатор), а "1384" -- номер процесса (управление процессами осуществляется системой). Завершить задание/процесс ("прихлопнуть") можно либо командой kill %1, либо kill 1384. Спасибо S. C. |
disown
Удаляет задание из таблицы активных заданий командной оболочки.
fg, bg
Команда fg переводит задание из фона на передний план. Команда bg перезапускает приостановленное задание в фоновом режиме. Если эти команды были вызваны без указания номера задания, то они воздействуют на текущее исполняющееся задание.
wait
Останавливает работу сценария до тех пор пока не будут завершены все фоновые задания или пока не будет завершено задание/процесс с указанным номером задания/PID процесса. Возвращает код завершения указанного задания/процесса.
Вы можете использовать команду wait для предотвращения преждевременного завершения сценария до того, как завершит работу фоновое задание.
Пример 11-23. Ожидание завершения процесса перед тем как продолжить работу
#!/bin/bash
ROOT_UID=0 # Только пользователь с $UID = 0 имеет привилегии root.
E_NOTROOT=65
E_NOPARAMS=66
if [ "$UID" - ne "$ROOT_UID" ]
then
echo "Для запуска этого сценария вы должны обладать привилегиями root."
exit $E_NOTROOT
fi
if [ - z "$1" ]
then
echo "Порядок использования: `basename $0` имя-файла"
exit $E_NOPARAMS
fi
echo "Обновляется база данных 'locate'..."
echo "Это может занять продолжительное время."
updatedb /usr & # Должна запускаться с правами root.
wait
# В этом месте сценарий приостанавливает свою работу до тех пор, пока не отработает 'updatedb'.
# Желательно обновить базу данных перед тем как выполнить поиск файла.
locate $1
# В худшем случае, без команды wait, сценарий завершил бы свою работу до того,
# как завершила бы работу утилита 'updatedb',
# сделав из нее "осиротевший" процесс.
exit 0
Команда wait может принимать необязательный параметр -- номер задания/процесса, например, wait %1 или wait $PPID. См. таблицу идентификации заданий.
| При запуске команды в фоне из сценария может возникнуть ситуация, когда сценарий приостанавливает свою работу до тех пор, пока не будет нажата клавиша ENTER. Это, кажется, происходит с командами, делающими вывод на stdout. Такое поведение может вызывать раздражение у пользователя. #!/bin/bash # test. sh ls - l & echo "Done." bash$ ./test. sh Done. [*****@***test-scripts]$ total 1 - rwxr-xr-x 1 bozo bozo 34 Oct 11 15:09 test. sh _ Разместив команду wait, после запуска фонового задания, можно предотвратить такое поведение сценария. #!/bin/bash # test. sh ls - l & echo "Done." wait bash$ ./test. sh Done. [*****@***test-scripts]$ total 1 - rwxr-xr-x 1 bozo bozo 34 Oct 11 15:09 test. sh Перенаправление вывода в файл или даже на устройство /dev/null также снимает эту проблему. |
suspend
Действует аналогично нажатию на комбинацию клавиш Control+-Z, за исключением того, что она приостанавливает работу командной оболочки.
logout
Завершает сеанс работы командной оболочки, можно указать необязательный код завершения.
times
Выдает статистику исполнения команд в единицах системного времени, в следующем виде:
0m0.020s 0m0.020s
Имеет весьма ограниченную сферу применения, так как сценарии крайне редко подвергаются профилированию.
kill
Принудительное завершение процесса путем передачи ему соответствующего сигнала (см. Пример 13-4).
Пример 11-24. Сценарий, завершающий себя сам с помощью команды kill
#!/bin/bash
# self-destruct. sh
kill $$ # Сценарий завершает себя сам.
# Надеюсь вы еще не забыли, что "$$" -- это PID сценария.
echo "Эта строка никогда не будет выведена."
# Вместо него на stdout будет выведено сообщение "Terminated".
exit 0
# Какой код завершения вернет сценарий?
#
# sh self-destruct. sh
# echo $?
# 143
#
# 143 = 128 + 15
# сигнал TERM
| Команда kill - l выведет список всех сигналов. Команда kill -9 -- это "жесткий kill", она используется, как правило, для завершения зависших процессов, которые упорно отказываются "умирать", отвергая простой kill. Иногда достаточно подать команду kill -15. "Процессы-зомби", т. е. процессы, "родители" которых уже завершили работу, не могут быть "убиты" таким способом (невозможно "убить" "мертвого"), рано или поздно с ними "расправится" процесс init. |
command
Директива command COMMAND запрещает использование псевдонимов и функций с именем "COMMAND".
| Это одна из трех директив командного интерпретатора, которая влияет на обработку команд. Другие две -- builtin и enable. |
builtin
Конструкция builtin BUILTIN_COMMAND запускает внутреннюю команду "BUILTIN_COMMAND", на время запрещая использование функций и внешних системных команд с тем же именем.
enable
Либо запрещает, либо разрешает вызов внутренних команд. Например, enable - n kill запрещает использование внутренней команды kill, в результате, когда интерпретатор встретит команду kill, то он вызовет внешнюю команду kill, т. е. /bin/kill.
Команда enable - a выведет список всех внутренних команд, указывая для каждой -- действительно ли она разрешена. Команда enable - f filename загрузит внутренние команды как разделяемую библиотеку (DLL) из указанного объектного файла. [26].
autoload
Перенесена в Bash из ksh. Если функция объявлена как autoload, то она будет загружена из внешнего файла в момент первого вызова. [27] Такой прием помогает экономить системные ресурсы.
Обратите внимание: autoload не является частью ядра Bash. Ее необходимо загрузить с помощью команды enable - f (см. выше).
Таблица 11-1. Идентификация заданий
Нотация | Описание |
%N | Номер задания [N] |
%S | Вызов (командная строка) задания, которая начинается со строки S |
%?S | Вызов (командная строка) задания, которая содержит строку S |
%% | "текущее" задание (последнее задание приостановленное на переднем плане или запущенное в фоне) |
%+ | "текущее" задание (последнее задание приостановленное на переднем плане или запущенное в фоне) |
%- | Последнее задание |
$! | Последний фоновый процесс |
Глава 12. Внешние команды, программы и утилиты
Благодаря стандартизации набора команд UNIX-систем, сценарии, на языке командной оболочки, могут быть легко перенесены из системы в систему практически без изменений. Мощь сценариев складывется из наборв системных команд и директив командной оболочки с простыми программными конструкциями.
12.1. Базовые команды
Первая команда, с которой сталкиваются новички
ls
Команда вывода "списка" файлов. Многие недооценивают всю мощь этой скромной команды. Например, с ключом -R, рекурсивный обход дерева каталогов, командв ls выводит содержимое каталогов в виде древовидной структуры. Вот еще ряд любопытных ключей (опций) команды ls: - S -- сортировка по размеру файлов, - t -- сортировка по времени последней модификации файла и - i -- выводит список файлов с их inode (см. Пример 12-3).
Пример 12-1. Создание оглавления диска для записи CDR, с помощью команды ls
#!/bin/bash
# burn-cd. sh
# Сценарий, автоматизирующий процесс прожигания CDR.
SPEED=2 # Если ваше "железо" поддерживает более высокую скорость записи -- можете увеличить этот параметр
IMAGEFILE=cdimage. iso
CONTENTSFILE=contents
DEFAULTDIR=/opt # В этом каталоге находятся файлы, которые будут записаны на CD.
# Каталог должен существовать.
# Используется пакет "cdrecord" от Joerg Schilling.
# (http://www. fokus. gmd. de/nthp/employees/schilling/cdrecord. html)
# Если этот сценарий предполагается запускать с правами обычного пользователя,
#+ то необходимо установить флаг suid на cdrecord
#+ (chmod u+s /usr/bin/cdrecord, эта команда должна быть выполнена root-ом).
if [ - z "$1" ]
then
IMAGE_DIRECTORY=$DEFAULTDIR
# Каталог по-умолчанию, если иной каталог не задан из командной строки.
else
IMAGE_DIRECTORY=$1
fi
# Создать файл "table of contents".
ls - lRF $IMAGE_DIRECTORY > $IMAGE_DIRECTORY/$CONTENTSFILE
# Ключ "l" -- "расширенный" формат вывода списка файлов.
# Ключ "R" -- рекурсивный обход дерева каталогов.
# Ключ "F" -- добавляет дополнительные метки к именам файлов (к именам каталогов добавдяет оконечный символ /).
echo "Создано оглавление."
# Создать iso-образ.
mkisofs - r - o $IMAGFILE $IMAGE_DIRECTORY
echo "Создан iso-образ файловой системы ISO9660 ($IMAGEFILE)."
# "Прожигание" CDR.
cdrecord - v - isosize speed=$SPEED dev=0,0 $IMAGEFILE
echo "Запись диска."
echo "Наберитесь терпения, это может потребовать некоторого времени."
exit 0
cat, tac
cat -- это акроним от concatenate, выводит содержимое списка файлов на stdout. Для объединения файлов в один файл может использоваться в комбинации с операциями перенаправления (> или >>).
# Порядок работы с 'cat'
cat filename # Вывод содержимого файла.
cat file.1 file.2 file.3 > file.123 # Объединение содержимого 3-х файлов в одном.
Ключ - n, команды cat, вставляет порядковые номера строк в выходном файле. Ключ - b -- нумерут только не пустые строки. Ключ - v выводит непечатаемые символы в нотации с символом ^. Ключ - s заменяет несколько пустых строк, идущих подряд, одной пустой строкой.
см. также Пример 12-21 and Пример 12-17.
tac -- выводит содержимое файлов в обратном порядке, от последней строки к первой.
rev
выводит все строки файла задом наперед на stdout. Это не то же самое, что tac. Команда rev сохраняет порядок следования строк, но переворачивает каждую строку задом наперед.
bash$
cat file1.txt
Это строка 1.
Это строка 2.
bash$
tac file1.txt
Это строка 2.
Это строка 1.
bash$
rev file1.txt
.1 акортс отЭ
.2 акортс отЭ
cp
Команда копирования файлов. cp file1 file2 скопирует file1 в file2, перезаписав file2 если он уже существовал (см. Пример 12-5).
| С флагами - a и - r, или - R выполняет копирование дерева каталогов. |
mv
Команда перемещения файла. Эквивалентна комбинации команд cp и rm. Может использоваться для перемещения большого количества файлов или для переименования каталогов. Примеры использования команды mv вы найдете в Пример 9-17 и Пример A-3.
| При использовании в неинтерактивных сценариях, команде mv следует передавать ключ - f, чтобы подавить запрос подтверждения на перемещение. Если в качестве каталога назначения указан существующий каталог, то перемещаемый каталог становится подкаталогом каталога назначения.. bash$ mv source_directory target_directory bash$ ls - lF target_directory total 1 drwxrwxr-x 2 bozo bozo 1024 May 28 19:20 source_directory/ |
rm
Удаляет (remove) файл(ы). Ключ - f позволяет удалять даже файлы ТОЛЬКО-ДЛЯ-ЧТЕНИЯ и подавляет запрос подтверждения на удаление.
| С ключом - r, удаляет все файлы в подкаталогах. |
rmdir
Удаляет каталог. Удаляемый каталог не должен содержать файлов, включая "скрытые файлы", [28] иначе каталог не будет удален.
mkdir
Создает новый каталог, например: mkdir - p project/programs/December создает каталог с заданным именем в требуемом каталоге. Ключ -p позволяет создавать промежуточные родительские каталоги.
chmod
Изменяет атрибуты существующего файла (см. Пример 11-11).
chmod +x filename
# Делает файл "filename" доступным для исполнения всем пользователям.
chmod u+s filename
# Устанавливается бит "suid" для "filename".
# В результате, любой пользователь сможет запустить "filename" с привилегиями владельца файла.
# (Это не относится к файлам-сценариям на языке командной оболочки.)
chmod 644 filename
# Выдает право на запись/чтение владельцу файла "filename", и право на чтение
# всем остальным
# (восьмеричное число).
chmod 1777 directory-name
# Выдает право на чтение, запись и исполнение файлов в каталоге,
# дополнительно устанавливает "sticky bit".
# Это означает, что удалять файлы в этом каталоге могут только владельцы файлов,
# владелец каталога и, само собой разумеется, root.
chattr
Изменяет атрибуты файла. Эта команда подобна команде chmod, за исключением синтаксиса вызова, и работает исключительно в файловой системе ext2.
ln
Создает ссылку на существующий файл. Позволяет задавать несколько имен одному и тому же файлу и представляет из себя превосходную альтернативу "псевдонимам" (алиасам) (см. Пример 4-6).
Чаще всего команда ln используется с ключом - s, который служит для создания символической (symbolic), или "мягкой" ("soft") ссылки. Без этого флага, команда создает полноценную копию файла. С ключом -- только ссылку, указывающую на заданный файл. Дополнительное преимущество ключа - s состоит в том, что он позволяет создавать ссылки на файлы, расположенные в других файловых системах.
Синтаксис команды достаточно прост. Например, команда: ln - s oldfile newfile создаст ссылку, с именем newfile, на существующий файл oldfile, .
man, info
Команды доступа к справочным и информационным страницам по системным командам и установленным программам и утилитам. Как правило, страницы info содержат более подробную информацию, чем man.
12.2. Более сложные команды
Команды для более опытных пользователей
find
-exec COMMAND \;
Для каждого найденого файла, соответствующего заданному шаблону поиска, выполняет команду COMMAND. Командная строка должна завершаться последовательностью символов \; (здесь символ ";" экранирован обратным слэшем, чтобы информировать командную оболочку о том, что символ ";" должен быть передан команде find как обычный символ). Если COMMAND содержит {}, то find подставляет полное имя найденого файла вместо "{}".
bash$
find ~/ - name '*.txt'
/home/bozo/.kde/share/apps/karm/karmdata. txt
/home/bozo/misc/irmeyc. txt
/home/bozo/test-scripts/1.txt
find /home/bozo/projects - mtime 1
# Найти все файлы в каталоге /home/bozo/projects и вложенных подкаталогах,
#+ которые изменялись в течение последних суток.
#
# mtime = время последнего изменения файла
# ctime = время последнего изменения атрибутов файла (через 'chmod' или как-то иначе)
# atime = время последнего обращения к файлу
DIR=/home/bozo/junk_files
find "$DIR" - type f - atime +5 - exec rm {} \;
# Удалить все файлы в каталоге "/home/bozo/junk_files"
#+ к которым не было обращений в течение последних 5 дней.
#
# "-type filetype", где
# f = обычный файл
# d = каталог, и т. п.
# (Полный список ключей вы найдете в 'man find'.)
find /etc - exec grep '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \;
# Поиск всех IP-адресов (xxx. xxx. xxx. xxx) в файлах каталога /etc.
# Однако эта команда выводит не только IP-адреса, как этого избежать?
# Примерно так:
find /etc - type f - exec cat '{}' \; | tr - c '.[:digit:]' '\n' \
| grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
# [:digit:] -- один из символьных классов
# введен в стандарт POSIX 1003.2.
# Спасибо S. C.
| Не следует путать опцию - exec команды find с внутренней командой Bash -- exec. |
Пример 12-2. Badname, удаление файлов в текущем каталоге, имена которых содержат недопустимые символы и пробелы.
#!/bin/bash
# Удаление файлов в текущем каталоге, чьи имена содержат недопустимые символы.
for filename in *
do
badname=`echo "$filename" | sed - n /[\+\{\;\"\\\=\?~\(\)\<\>\&\*\|\$]/p`
# Недопустимые символы в именах файлов: + { ; " \ = ? ~ ( ) < > & * | $
rm $badname 2>/dev/null # Сообщения об ошибках "выстреливаются" в никуда.
done
# Теперь "позаботимся" о файлах, чьи имена содержат пробельные символы.
find. - name "* *" - exec rm - f {} \;
# На место "{}", find подставит полное имя файла.
# Символ '\' указывает на то, что ';' интерпретируется как обычный символ, а не как конец команды.
exit 0
#---
# Строки, приведенные ниже, не будут выполнены, т. к. выше стоит команда "exit".
# Альтернативный вариант сценария:
find. - name '*[+{;"\\=?~()<>&*|$ ]*' - exec rm - f '{}' \;
exit 0
# (Спасибо S. C.)
Пример 12-3. Удаление файла по его номеру inode
#!/bin/bash
# idelete. sh: Удаление файла по номеру inode.
# Этот прием используется в тех случаях, когда имя файла начинается с недопустимого символа,
#+ например, ? или -.
ARGCOUNT=1 # Имя файла должно быть передано в сценарий.
E_WRONGARGS=70
E_FILE_NOT_EXIST=71
E_CHANGED_MIND=72
if [ $# - ne "$ARGCOUNT" ]
then
echo "Порядок использования: `basename $0` filename"
exit $E_WRONGARGS
fi
if [ ! - e "$1" ]
then
echo "Файл \""$1"\" не найден."
exit $E_FILE_NOT_EXIST
fi
inum=`ls - i | grep "$1" | awk '{print $1}'`
# inum = номер inode (index node) файла
# Каждый файл имеет свой inode, где хранится информация о физическом расположении файла.
echo; echo - n "Вы совершенно уверены в том, что желаете удалить \"$1\" (y/n)? "
# Ключ '-v' в команде 'rm' тоже заставит команду вывести подобный запрос.
read answer
case "$answer" in
[nN]) echo "Передумали?"
exit $E_CHANGED_MIND
;;
*) echo "Удаление файла \"$1\".";;
esac
find. - inum $inum - exec rm {} \;
echo "Файл "\"$1"\" удален!"
exit 0
Дополнительные примеры по использованию команды find вы найдете в Пример 12-22, Пример 3-4 и Пример 10-9. В страницах справочного ркуоводства (man find) вы найдете более подробную информацию об этой достаточно сложной и мощной команде.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |


