Шрифт:
done
$ cat footnote
UNIX is not an acronym
$ replace UNIX Unix footnote
$ cat footnote
Unix is not an acronym
$
(Вспомните: если список в цикле
for
пуст, то по умолчанию он равен $*
.) Мы использовали @
вместо /
для разбиения в команде подстановки, поскольку менее вероятно, что @
вступит в конфликт с входной строкой. Команда replace
устанавливает PATH
равным /bin:/usr/bin
, исключая $HOME/bin
. Это означает, что overwrite
должна находиться в /usr/bin
, чтобы команда replace
сработала. Мы сделали такое предположение для простоты; если вы не можете поместить overwrite
в /usr/bin
, вам придется добавить $HOME/bin
к PATH
в команде replace
или явно задать полное имя overwrite
. В дальнейшем будем полагать, что команды, которые мы создаем, находятся в /usr/bin
, где им и следует быть. Упражнение 5.17
Почему команда
overwrite
не использует сигнал 0 в команде trap
, чтобы файлы удалялись при выходе из нее? Подсказка: попробуйте нажать клавишу DEL во время выполнения следующей программы:
trap "echo exiting; exit 1" 0 2
sleep 10
Упражнение 5.18
Добавьте флаг
– v
к команде replace
для вывода всех измененных строк на /dev/tty
. Подсказка:
s/$left/$right/g $vflag
. Упражнение 5.19
Увеличьте надежность команды
replace
, чтобы ее выполнение не зависело от символов в строке замены. Упражнение 5.20
Можно ли использовать
replace
для замены i
на index
всюду в программе? Какие вы внесли бы изменения, чтобы добиться этого? Упражнение 5.21
Достаточно ли команда
replace
эффективна и удобна, чтобы находиться в каталоге /usr/bin
? Не лучше ли вводить по мере необходимости подходящие команды редактора sed
(да или нет)? Обоснуйте свой ответ. Упражнение 5.22
(Усложненное.) Команда
$ overwrite файл 'who | sort'
не выполняется. Объясните причину этого и исправьте ее. Подсказка: посмотрите
eval
в справочном руководстве по sh(1)
. Как ваше решение повлияет на интерпретацию специальных символов в команде? 5.6 Команда
zap
: уничтожение процесса по имени Команда
kill
только завершает процесс с указанным номером. Если нужно уничтожить определенный фоновый процесс, обычно приходится выполнить команду ps
, чтобы узнать номер процесса, а затем ввести этот номер в качестве аргумента для команды kill
. Однако нелепо иметь программу, выдающую номер процесса, который сразу же передается вручную другой программе. Имеет смысл написать программу, скажем zap
, для автоматического выполнения такой работы. Здесь, правда, есть одно препятствие: уничтожение процессов опасно, поэтому следует принять меры для обеспечения сохранности нужных процессов. Хорошей защитой всегда служат диалоговое выполнение zap и использование команды pick
для выбора "жертв". Кратко напомним вам о команде
pick
: она выдает поочередно свои аргументы, спрашивая ответ у пользователя; если ответ — y
, то аргумент выводится (команда pick
обсуждается в следующем разделе). В нашем случае pick
используется для подтверждения, что процессы, выбранные по имени, — именно те, которые пользователь хочет уничтожить:
$ cat zap
# zap pattern: kill all processes matching pattern
# BUG in this version
PATH=/bin:/usr/bin
case $# in
0) echo 'Usage: zap pattern' 1>&2; exit 1
esac
kill `pick \`ps -ag | grep "$*"\` | awk '{print $1}'`
Обратите внимание на вложенные знаки слабого ударения, защищенные символами обратной дробной черты,
awk
программа выделяет номер процесса из выходных данных команды ps
, выбранной с помощью pick
:
$ sleep 1000 &
2216
$ ps -ag
PID TTY TIME CMD
...
2216 0 0:00 sleep 1000
...
$ zap sleep
2216?
0? q
Что происходит?
$
Проблема состоит в том, что выходные данные команды
ps
разбиты на слова, которые воспринимаются и обрабатываются командой pick
как отдельные аргументы вместо того, чтобы обрабатываться сразу по строке. Обычная процедура интерпретатора заключается в разбиении строк на аргументы с границами пробел/не пробел, как показано ниже: