Главная » Программирование для UNIX » Циклы в программах оболочки UNIX

0

Фактически  оболочку можно назвать  языком  программирования: в ней  есть  переменные, циклы, принятие решений и т. д. Основы  организации циклов будут рассмотрены в этом разделе, а об управляющей логике программы поговорим в главе 5.

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

for  var  in  список слов

do

done

команды

Например, с помощью оператора for  можно организовать вывод  имен  файлов по одному  на строке:

$ for  i in  *

> do

>            echo $i

> done

На месте i может стоять любая переменная оболочки, но традиционно это i. Обратите внимание, что доступ  к значению переменной обеспечивается посредством $i, но цикл for ссылается на переменную как на

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  &

$

Мы организовали конвейерное перенаправление в pr и lpr только для  того, чтобы показать, что стандартный вывод команд внутри цикла for становится стандартным выводом самого  for. С помощью параметра –h команды pr был  создан красивый заголовок для вывода (два  вложенных  вызова pwd). И еще мы запустили всю эту последовательность команд  в асинхронном режиме (&), так  что нам не надо ожидать ее завершения; & применяется сразу  ко всему циклу и конвейеру.

Авторы предпочитают такой формат оператора for, который использован  в примере, но возможны и другие варианты. Приведем основное ограничение: do и done воспринимаются как зарезервированные слова, только если  они появляются после  символа новой  строки или точки с запятой. В зависимости от размеров for, иногда бывает удобнее  записать все в одной строке:

for  i in  список; do команды; done

Цикл for  следует использовать для  большого  количества команд и в случаях, когда обработка встроенного аргумента отдельной командой неприемлема.

Но не применяйте его для  одной  команды, которая будет  перебирать имена файлов:

# Плохая  идея: for  i  in  $*

do

done

chmod  +x $i

хуже, чем

chmod  +x $*

потому что цикл for  выполняет отдельную команду chmod для  каждого файла,  что  требует  значительно  бoльших компьютерных  ресурсов. (Убедитесь, что вы понимаете различие между

for  i in  *

где перебираются все файлы в текущем каталоге, и

for  i in  $*

где перебираются все аргументы командного файла.)

Список аргументов для  цикла for  обычно образуется по шаблону для  имен  файлов, но может быть  получен и другим способом. Это может быть

$ for  i in  `cat …`

Но  можно просто  ввести аргументы с  терминала. Например, ранее  в этой  же  главе была  создана группа программ для вывода в несколько колонок (они были  названы 2, 3 и т. д.).  Они представляют собой просто ссылки (links) на один  и тот же файл, которые могут быть  сделаны (после того как единожды был записан файл 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  &

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

Источник: Керниган Б., Пайк Р., UNIX. Программное окружение. – Пер. с англ. – СПб: Символ-Плюс, 2003. – 416 с., ил.

По теме:

  • Комментарии