Внутреннее устройство Linux
Шрифт:
примечание
Каждое условие должно завершаться двойной точкой с запятой (;;), чтобы не возникло синтаксической ошибки.
11.6. Циклы
В оболочке Bourne shell существуют два типа циклов: цикл for и цикл while.
11.6.1. Цикл for
Цикл for (который является циклом «для каждого») самый распространенный. Вот пример:
#!/bin/sh
for str in one two three four; do
echo $str
done
В этом листинге слова for, in, do
1. Присваивает переменной str первое (one) из четырех значений, следующих после слова in и разделенных символами пробела.
2. Запускает команду echo, расположенную между словами do и done.
3. Возвращается к строке for, присваивает переменной str следующее значение (two), выполняет команды между словами do и done, а затем повторяет процесс до тех пор, пока не закончатся значения, следующие после ключевого слова in.
Результат работы этого сценария выглядит так:
one
two
three
four
11.6.2. Цикл while
Цикл while в оболочке Bourne shell использует коды выхода, подобно условному оператору if. Например, такой сценарий выполняет десять итераций:
#!/bin/sh
FILE=/tmp/whiletest.$$;
echo firstline > $FILE
while tail -10 $FILE | grep -q firstline; do
# add lines to $FILE until tail -10 $FILE no longer prints "firstline"
echo -n Number of lines in $FILE:' '
wc -l $FILE | awk '{print $1}'
echo newline >> $FILE
done
rm -f $FILE
Здесь проверяется код выхода команды grep –q firstline. Как только код выхода становится ненулевым (в данном случае, когда строка firstline не будет появляться в десяти последних строках файла $FILE), цикл завершается.
Можно выйти из цикла while с помощью инструкции break. В оболочке Bourne shell есть также цикл until, который действует подобно циклу while, за исключением того, что он завершается, когда встречает нулевой код выхода, а не код, не равный 0. Однако не следует использовать слишком часто циклы while и until. В действительности, если вам необходимо применить цикл while, возможно, лучше воспользоваться языком awk или Python.
11.7. Подстановка команд
Оболочка Bourne shell может перенаправлять стандартный вывод какой-либо команды обратно в командную строку оболочки. То есть можно использовать вывод команды в качестве аргумента для другой команды или же сохранить вывод команды в переменной оболочки, поместив команду внутрь выражения $.
Следующий пример сохраняет команду внутри переменной FLAGS. Жирным шрифтом во второй строке выделена подстановка команды.
#!/bin/sh
FLAGS=$(grep ^flags /proc/cpuinfo | sed 's/.*://' | head -1)
echo Your processor supports:
for f in $FLAGS; do
case $f in
fpu) MSG="floating point unit"
;;
3dnow) MSG="3DNOW graphics extensions"
;;
mtrr) MSG="memory type range register"
;;
*) MSG="unknown"
;;
esac
echo $f: $MSG
done
Данный пример достаточно сложен, поскольку он показывает возможность использования как одинарных кавычек, так и каналов внутри подстановки. Результат команды grep отправляется в команду sed (подробности см. в подразделе 11.10.3),
которая удаляет все, что соответствует выражению .*:, а затем результат команды sed передается команде head.Используя подстановку команд, очень легко сделать лишнее. Например, не применяйте в сценариях выражение $(ls), поскольку оболочка выполняет развертывание символа * быстрее. Кроме того, если вы желаете применить команду к нескольким именам файлов, которые вы получаете в результате работы команды find, попробуйте использовать канал для команды xargs, а не подстановку или же параметр –exec (см. подраздел 11.10.4).
примечание
Традиционный синтаксис для подстановки команды: размещение команды внутри «обратных черточек» (``). Такой вариант вы встретите во многих сценариях. Синтаксис $ является новой формой, которая следует стандарту POSIX, легче записывается и читается.
11.8. Управление временным файлом
Иногда бывает необходимо создать временный файл, чтобы собрать вывод для его использования в следующей команде. При создании такого файла убедитесь в том, что имя этого файла достаточно индивидуально, чтобы другие команды случайно не выполнили запись в него.
Приведу пример того, как использовать команду mktemp для создания имен временных файлов. Данный сценарий показывает аппаратные прерывания, которые возникли за последние две секунды.
#!/bin/sh
TMPFILE1=$(mktemp /tmp/im1.XXXXXX)
TMPFILE2=$(mktemp /tmp/im2.XXXXXX)
cat /proc/interrupts > $TMPFILE1
sleep 2
cat /proc/interrupts > $TMPFILE2
diff $TMPFILE1 $TMPFILE2
rm -f $TMPFILE1 $TMPFILE2
Аргумент команды mktemp является шаблоном. Команда mktemp превращает XXXXXX в уникальный набор символов и создает пустой файл с таким именем. Обратите внимание на то, что этот сценарий использует имена переменных для хранения имен файлов, поэтому, чтобы изменить имя файла, необходимо изменить всего одну строку.
примечание
Не все варианты Unux содержат команду mktemp. Если у вас возникнут проблемы с переносимостью, лучше установить GNU-пакет coreutils для вашей операционной системы.
Еще одна проблема сценариев, которые используют временные файлы, такова: если выполнение сценария будет прервано, временные файлы могут остаться в системе. В предыдущем примере, если нажать сочетание клавиш Ctrl+C до начала второй команды, то в каталоге /tmp останется временный файл. Избегайте этого по возможности. Старайтесь использовать команду trap для создания обработчика сигнала, который будет перехватывать сигнал от нажатия клавиш Ctrl+C и удалять временные файлы, как в этом примере:
#!/bin/sh
TMPFILE1=$(mktemp /tmp/im1.XXXXXX)
TMPFILE2=$(mktemp /tmp/im2.XXXXXX)
trap "rm -f $TMPFILE1 $TMPFILE2; exit 1" INT
—snip—
Вы должны использовать команду exit в таком обработчике, чтобы явным образом завершить выполнение сценария, а иначе оболочка продолжит его обычную работу после выполнения обработчика сигнала.
примечание
Не обязательно передавать аргументы команде mktemp. Если их нет, то шаблон будет начинаться с префикса /tmp/tmp.