Выполните упражнение 2.9.
В следующем сценарии вы обращаетесь к файлу file_one (для проверки его наличия, и если файл не существует, создаете его) и затем удаляете файл file_two. Далее И-список проверяет наличие каждого файла и между делом выводит на экран кое-какой текст.
#!/bin/sh
touch file_one
rm -f file_two
if [ -f file_one ] && echo "hello" [ -f file_two ] && echo " there"
then
echo "in if"
else
echo "in else"
fi
exit 0
Попробуйте выполнить сценарий, и вы получите следующий вывод:
hello
in else
Как это работает
Команды touch
и rm
гарантируют, что файлы в текущем каталоге находятся в известном состоянии. Далее И-список выполняет команду [ -f file one ]
, которая возвращает значение true
, потому что вы только что убедились в наличии файла. Поскольку предыдущий оператор завершился успешно, теперь выполняется команда echo
. Она тоже завершается успешно (echo
всегда возвращает true
). Затем выполняется третья проверка [ -f file_two ]
. Она возвращает значение false
, т.к. файл не существует. Поскольку последняя команда вернула false
, заключительная команда echo
не выполняется. В результате И-список возвращает значение false
, поэтому в операторе if
выполняется вариант else
.
Эта конструкция позволяет выполнять последовательность команд до тех пор, пока одна из них не вернет значение true, и далее не выполняется ничего более. У нее следующая синтаксическая запись:
оператор1
||
оператор2
||
оператор3
||
...
Операторы выполняются слева направо. Если очередной оператор возвращает значение false
, выполняется следующий за ним оператор. Это продолжается до тех пор, пока очередной оператор не вернет значение true
, после этого никакие операторы уже не выполняются.
ИЛИ-список очень похож на И-список, за исключением того, что правило для выполнения следующего оператора — выполнение предыдущего оператора со значением false
.
Рассмотрим упражнение 2.10.
Скопируйте сценарий из предыдущего упражнения и измените затененные строки следующим образом.
#!/bin/sh
rm -f file_one
if [ -f file_one ] || echo "hello" || echo " there" then
echo "in if"
else
echo "in else"
fi
exit 0
В результате выполнения данного сценария будет получен следующий вывод:
hello
in if
Как это работает
В первых двух строках просто задаются файлы для остальной части сценария. Первая команда списка [ -f file one ]
возвращает значение false
, потому что файла в каталоге нет. Далее выполняется команда echo
. Вот это да — она возвращает значение true
, и больше в ИЛИ-списке не выполняются никакие команды. Оператор if
получает из списка значение true, поскольку одна из команд ИЛИ-списка (команда echo
) вернула это значение.
Результат, возвращаемый обоими этими списками, — это результат последней выполненной команды списка.
Описанные конструкции списков выполняются так же, как аналогичные конструкции в языке С, когда проверяются множественные условия. Для определения результата выполняется минимальное количество операторов. Операторы, не влияющие на конечный результат, не выполняются. Обычно этот подход называют оптимизацией вычислений (short circuit evaluation).
Комбинирование этих двух конструкций — высшее блаженство для любителей логических задач. Попробуйте проанализировать следующий список:
[ -f file_one ] && команда в случае true || команда в случае false
В нем будет выполняться первая команда в случае истинности проверки и вторая команда в противном случае. Всегда лучше всего поэкспериментировать с этими довольно необычными списками, и, как правило, вам придется использовать скобки для изменения порядка вычислений.
Если вы хотите применить несколько операторов в том месте программного кода, где разрешен только один, например в ИЛИ-списке или И-списке, то можете сделать это, заключив операторы в фигурные скобки {}
и создав тем самым операторный блок. Например, в приложении, представленном далее в этой главе, вы увидите следующий фрагмент программного кода:
get_confirm && {
grep -v "$cdcatnum" $tracks_file > $temp_file
cat $temp_file > $tracks_file
echo
add record_tracks
}
Функции
В командной оболочке можно определять функции, и, если вы пишете сценарии любого размера, функции можно применять для структурирования кода.
Как альтернативу можно использовать разбиение большого сценария на много маленьких, каждый из которых выполняет небольшую задачу. У этого подхода есть несколько недостатков: выполнение вложенного в сценарий другого сценария будет гораздо медленнее, чем выполнение функции. Значительно труднее возвращать результаты, и может появиться большое количество маленьких сценариев. Следует рассмотреть наименьшую практически самостоятельную часть вашего сценария и использовать ее как эталон для того, чтобы определить, когда возникает необходимость разбиения большого сценария на коллекцию меньших по размеру сценариев.