Книга: UNIX — универсальная среда программирования

3.8 Циклы в shell-программах

3.8 Циклы в shell-программах

Язык shell — действительно язык программирования: в нем есть переменные, циклы, ветвления и т.п. Здесь мы обсудим основные циклы, а структуры управления рассмотрим более подробно в гл. 5.

Типичным считается цикл по последовательности имен файлов, и оператор for языка shell является единственной структурой управления, которую обычно задают с терминала, а не помещают в файл для последующего выполнения. Синтаксис оператора for таков:

for перем in список_слов
do
 команды
done

Например, для получения эха имен файлов по одному на строке достаточно задать:

$ for i in *
> do
>  echo $i
> done

Вместо 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?
$

Очевидно, данный цикл следует поместить в командный файл, чтобы уменьшить ввод в следующий раз (ведь если вы что-то сделали дважды, вероятно, вы сделаете это и в третий раз).

Упражнение 3.15

Если цикл с командой diff хранится в командном файле, поместите ли вы туда команду pick? Объясните, почему.

Упражнение 3.16

Что произойдет, если последняя строка приведенного цикла будет иметь вид:

> done | pr | lpr &

т.е. кончаться амперсандом? Попробуйте сделать прогноз, а затем проверьте его.

Оглавление книги


Генерация: 0.179. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз