Основы программирования в Linux
Проблема, связанная с переменнымиДанный сценарий исправляет наиболее очевидный дефект, а более тонкая проблема остается незамеченной. Запустите новый вариант сценария, но вместо ответа на вопрос просто нажмите клавишу <Enter> (или на некоторых клавиатурах клавишу <Return>). Вы получите сообщение об ошибке:
[: =: unary operator expectedЧто же не так? Проблема в первой ветви оператора
. Когда проверялась переменнаяif, она состояла из пустой строки. Следовательно, ветвь оператораtimeofdayвыглядела следующим образом:if<i>if [ = "yes" ]</i>и не представляла собой верное условие. Во избежание этого следует заключить имя переменной в кавычки:
<i>if [ "$timeofday" = "yes" ]</i>Теперь проверка с пустой переменной будет корректной:
<i>if [ "" = "yes" ]</i>Новый сценарий будет таким:
#!/bin/shecho "Is it morning? Please answer yes or no "read timeofday<i>if [ "$timeofday" = "yes" ]</i>thenecho "Good morning"elif [ "$timeofday" = "no" ]; thenecho "Good afternoon"else<i> echo "Sorry, $timeofday not recognized. Enter yes or no "</i>exit 1fiexit 0Этот вариант безопасен, даже если пользователь в ответ на вопрос просто нажмет клавишу <Enter>.
ПримечаниеЕсли вы хотите, чтобы команда
удалила новую строку в конце, наиболее легко переносимый вариант — применить командуecho(см. разд. "printf" далее в этой главе) вместо командыprintf. В некоторых командных оболочках применяется командаecho, но она поддерживается не всеми системами. В оболочке bash для запрета перехода на новую строку допускается командаecho -е, поэтому, если вы уверены, что вашему сценарию придется трудиться только в оболочке bash, предлагаем вам использовать следующий синтаксис:echo -necho -n "Is it morning? Please answer yes or no: "Помните о том, что нужно оставлять дополнительный пробел перед закрывающими кавычками, таким образом формируется зазор перед вводимым пользователем ответом, который в этом случае выглядит четче.
forПрименяйте конструкцию
для обработки в цикле ряда значений, которые могут представлять собой любое множество строк. Строки могут быть просто перечислены в программе или, что бывает чаще, представлять собой результат выполненной командной оболочкой подстановки имен файлов.forСинтаксис этого оператора прост:
<b>for</b> <i>переменная </i><b>in</b> <i>значения</i><b>do</b><i> операторы</i><b>done</b>Выполните упражнения 2.4 и 2.5.
Упражнение 2.4. Применение циклак фиксированным строкамforВ командной оболочке значения обычно представлены в виде строк, поэтому можно написать следующий сценарий:
#!/bin/shfor foo in bar fud 43doecho $foodoneexit 0В результате будет получен следующий вывод:
barfud43ПримечаниеЧто произойдет, если вы измените первую строку с
наfor foo in bar fud 43? Напоминаем, что вставка кавычек заставляет командную оболочку считать все, что находится между ними, единой строкой. Это один из способов сохранения пробелов в переменной.for foo in "bar fud 43"Как это работает
В данном примере создается переменная
и ей в каждом проходе циклаfooприсваиваются разные значения. Поскольку оболочка считает по умолчанию все переменные строковыми, применять строку 43 так же допустимо, как и строкуfor.fudУпражнение 2.5. Применение циклас метасимволамиforКак упоминалось ранее, цикл
обычно используется в командной оболочке вместе с метасимволами или знаками подстановки для имен файлов. Это означает применение метасимвола для строковых значений и предоставление оболочке возможности подставлять все значения на этапе выполнения.forВы уже видели этот прием в первом примере first. В сценарии применялись средства подстановки командной оболочки — символ
для подстановки имен всех файлов из текущего каталога. Каждое из этих имен по очереди используется в качестве значения переменной*внутри цикла$file.forДавайте бегло просмотрим еще один пример подстановки с помощью метасимвола. Допустим, что вы хотите вывести на экран все имена файлов сценариев в текущем каталоге, начинающиеся с буквы "f", и вы знаете, что имена всех ваших сценариев заканчиваются символами .sh. Это можно сделать следующим образом:
#!/bin/shfor file in $(ls f*.sh); dolpr $filedoneexit 0Как это работает
В этом примере показано применение синтаксической конструкции
, которая будет подробно обсуждаться далее (в разделе, посвященном выполнению команд). Обычно список параметров для цикла$(<i>команда</i>)задается выводом команды, включенной в конструкциюfor.$()