Вместо i
shell, но это обозначение традиционно. Заметьте, что значение переменной получается с помощью $i, однако в заголовке цикла переменную указывают как i. Мы задействовали * для выбора всех файлов текущего каталога, но можно использовать и любой другой список аргументов. Обычно нужно сделать что-нибудь более интересное, чем печать имен файлов. Нам часто приходилось сравнивать набор файлов с их предыдущими версиями, например старую версию гл. 2 (хранимую в каталоге old) с текущей:$ ls ch2. * | 5
ch2.1 ch2.2 ch2.3 ch2.4 ch2.5
ch2.6 ch2.7
$ for i in ch2.*
> do
> echo $i
> diff -b old/$i $i
> echo
> done | pr -h "diff `pwd`/old `pwd` | lpr &
3712
$
Выходной поток направлен по конвейеру через команды pr
lpr просто для того, чтобы показать, что это возможно: стандартный выходной поток программ, находящихся внутри цикла for, попадает в стандартный выходной поток самой команды for. С помощью флага -h в команде pr мы поместили в выходной поток заголовок с "архитектурными излишествами", используя два вложенных обращения к pwd. Вся последовательность команд запущена асинхронно (&), так что не нужно ждать ее окончания; & применяется ко всякому циклу и конвейеру.Мы предпочитаем указанный формат для цикла for
do и done распознаются как ключевые слова, только если они появляются сразу после перевода строки или точки с запятой. В зависимости от размера цикла for иногда лучше помещать все на одной строке:for i in список; do команды; done
Следует использовать цикл for
# Плохая идея:
for i in $*
do
chmod +x $i
done
Предпочтительнее сделать так:
chmod +x $*
поскольку в цикле for
chmod выполняется для каждого файла, что требует больших вычислительных ресурсов. (Убедитесь в том, что вы понимаете разницу между командамиfor i in *
в которой цикл выполняется по всем именам файлов текущего каталога, и
for i in $*
в которой цикл выполняется по всем аргументам командного файла.)
Список аргументов для цикла for
for i in `cat ...`
или просто вводом аргументов. Например, ранее в этой главе мы создали ряд программ для печати в несколько столбцов под именами 2
3 и т.д. Они являются связями с одним файлом, которые можно установить следующим образом (при условии, что программа 2 написана):$ for i in 3 4 5 6; do ln 2 $i; done
$
Цикл for
pick те файлы, которые будут сравниваться с файлами из каталога старых версий:$ for i in `pick ch2.*`
> do
> echo $i:
> diff old/$i $i
> done | pr | lpr
ch2.1? y
ch2.2
ch2.3
ch2.4? y
ch2.5? y
ch2.6?
ch2.7?
$
Очевидно, данный цикл следует поместить в командный файл, чтобы уменьшить ввод в следующий раз (ведь если вы что-то сделали дважды, вероятно, вы сделаете это и в третий раз).
Если цикл с командой diff
Что произойдет, если последняя строка приведенного цикла будет иметь вид:
> done | pr | lpr &
т.е. кончаться амперсандом? Попробуйте сделать прогноз, а затем проверьте его.
3.9 Программа bundle
Чтобы лучше понять, как создаются командные файлы, обратимся к такому примеру. Предположим, вы получили почту от приятеля с другой машины: "где-то!боб"
mail(1)), и он хотел бы скопировать командные файлы из вашего каталога bin. Самый простой способ их пересылки заключается в ответной почте, так что вы могли бы начать вводить:$ cd /usr/you/bin
$ for i in `pick *`
> do
> echo ============== Это файл $i ==============