Правила использования кавычек
Обычно параметры в сценариях отделяются неотображаемыми символами или знаками форматирования (например, пробелом, знаком табуляции или символом перехода на новую строку). Если вы хотите, чтобы параметр содержал один или несколько неотображаемых символов, его следует заключить в кавычки.
Поведение переменных, таких как $foo, заключенных в кавычки, зависит от вида используемых кавычек. Если вы заключаете в двойные кавычки $-представление переменной, оно во время выполнения командной строки заменяется значением переменной. Если вы заключаете его в одинарные кавычки или апострофы, никакой замены не происходит.
Пример 1.
В этом примере показано, как кавычки влияют на вывод переменной:
#!/bin/sh
myvar="Hi there"
echo $myvar
echo "$myvar"
echo '$myvar'
echo \$myvar
echo Enter some text
read myvar
echo '$myvar' $myvar
exit 0
Данный сценарий ведет себя следующим образом:
$ ./variable
Hi there
Hi there
$myvar
$myvar
Enter some text
Hello world
$myvar Hello World
В сценарии создается переменная myvar, и ей присваивается строка Hi there. Содержимое переменной выводится на экран с помощью команды echo, демонстрирующей, как символ $ раскрывает содержимое переменной. Применение двойных кавычек не влияет на раскрытие содержимого переменной, а одинарные кавычки и обратный слэш влияют. Показано использование команды read для получения строки от пользователя.
Переменные окружения
При старте сценария командной оболочки некоторым переменным присваиваются начальные значения из окружения или рабочей среды. Обычно такие переменные обозначают прописными буквами, чтобы отличать их в сценариях от определенных пользователем переменных (командной оболочки), которые принято обозначать строчными буквами. Например:
$НОМЕ Исходный каталог текущего пользователя
$РАТН Разделенный двоеточиями список каталогов для поиска команд
$PS1 Подсказка или приглашение командной строки. Часто это знак $, но в оболочке bash можно применять и более сложные варианты. Например, строка [\u@\h \w]$ — популярный стандарт, сообщающий в подсказке пользователю имя компьютера и текущий каталог, а также знак $.
$PS2 Дополнительная подсказка или приглашение, применяемое как приглашение для дополнительного ввода; обычно знак >
$# Количество передаваемых параметров
Переменные-параметры
Если сценарий вызывается с параметрами, создается несколько дополнительных переменных. Если параметры не передаются, переменная окружения $# равна 0.
Переменные-параметры перечислены в табл. 1.
Таблица 1
Переменная-параметр | Описание |
$1, $2, ... | Параметры, передаваемые сценарию |
$* | Список всех параметров в единственной переменной, разделенных первым символом из переменной окружения ifs. |
Условия
Основа всех языков программирования — средства проверки условий и выполнение различных действий с учетом результатов этой проверки. Рассмотрим условные конструкции, которые можно применять в сценариях командной оболочки, а затем познакомимся с использующими их управляющими структурами.
Сценарий командной оболочки может проверить код завершения любой команды, вызванной из командной строки, включая сценарии, написанные пользователями.
Команда test или [
На практике в большинстве сценариев широко используется команда [ или test -логическая проверка командной оболочки. В некоторых системах команды [ и test - синонимы, за исключением того, что при использовании команды [ для удобочитаемости применяется и завершающая часть ]. В программном коде команда [ упрощает синтаксис и делает его более похожим на другие языки программирования.
Поскольку команда test не часто применяется за пределами сценариев командной оболочки, многие пользователи ОС Linux, никогда раньше не писавшие сценариев пытаются создавать простые программы и называют их test. Если такая программа не работает, вероятно, она конфликтует с командой оболочки test.
Представим команду test на примере одного простейшего условия: проверки наличия файла. Для нее понадобится следующая команда: test -f <имя_файла>, поэтому в сценарии можно написать
if test -f fred.c then
fi
To же самое можно записать следующим образом:
if [ -f fred.c ] then
fi
Код завершения команды test (выполнено ли условие) определяет, будет ли выполняться условный программный код.
Необходимо вставлять пробелы между квадратной скобкой [ и проверяемым условием. Это легко усвоить, если запомнить, что вставить символ [ — это все равно, что написать test, а после имени команды всегда нужно вставлять пробел.
Если слово then записано в той же строке, что и if, нужно добавить точку с запятой для отделения команды test от then:
if [ -f fred.c ]; then fi
Варианты условий, которые используются в команде test, делятся на три типа:
· строковые сравнения,
· числовые сравнения,
· проверка файловых флагов.
Эти условия описаны в табл. 2.
Таблица 2. Условия
Варианты условий | Результат | |
Сравнения строк | ||
Строка1 = Строка 2 | True (истина), если строки одинаковы | |
Строка1 != Строка2 | True (истина), если строки разные | |
-n Строка | True (истина), если Строка не null | |
-z Строка | True (истина), если Строка null (пустая строка) | |
Сравнения чисел | ||
Выр1 -eq Выр2 | True (истина), если выражения равны | |
Выр1 -nе Выр2 | True (истина), если выражения не равны | |
Выр1 -gt Выр2 | True (истина), если Выр1 больше, чем Выр2 | |
Выр1 -gе Выр2 | True (истина), если Выр1 не меньше Выр2 | |
Выр1 -lt Выр2 | True (истина), если Выр1 меньше, чем Выр2 | |
Выр1 -le Выр2 | True (истина), если Выр1 не больше Выр2 | |
!Выражение | True (истина), если Выражение ложно, и наоборот | |
Файловые флаги | ||
-d файл | True (истина), если файл— каталог | |
-е файл | True (истина), если файл существует | |
-f файл | True (истина), если файл— обычный файл | |
-r файл | True (истина), если файл доступен для чтения | |
-s файл | True (истина), если файл ненулевого размера | |
-w файл | True (истина), если файл доступен для записи | |
-х файл | True (истина), если файл— исполняемый файл | |
Пример 2 тестирования состояния файла /bin/bash.
#!/bin/sh
if [ -f /bin/bash ]
then
echo "file /bin/bash exists"
fi
if [ -d /bin/bash ]
then
echo "/bin/bash is a directory"
else
echo "/bin/bash is NOT a directory"
fi
Для того чтобы тест мог оказаться истинным, предварительно, для проверки всех файловых флагов требуется наличие файла. Данный перечень включает только самые широко используемые опции команды test, полный список можно найти в интерактивном справочном руководстве.
Управляющие структуры
В командной оболочке есть ряд управляющих структур или конструкций, похожих на аналогичные структуры в других языках программирования.
В следующих разделах элемент синтаксической записи операторы— это последовательности команд, которые выполняются, когда или пока условие удовлетворяется или пока оно не удовлетворяется.
Оператор разветвления if
Оператор if очень прост: он проверяет результат выполнения команды и затем в зависимости от условия выполняет ту или иную группу операторов.
if условие then
операторы
else
операторы
fi
Наиболее часто оператор if применяется, когда задается вопрос, и решение принимается в зависимости от ответа.
Пример 3
#!/bin/sh
echo "Сейчас утро? Ответьте yes или no"
read timeofday
if [ $timeofday = "yes" ]; then
echo "Доброе утро"
else
echo "Добрый вечер"
fi
exit 0
В результате будет получен следующий вывод на экран:
Сейчас утро? Ответьте yes или no yes
yes
Доброе утро
$
В этом сценарии для проверки содержимого переменной timeofday применяется команда [. Результат оценивается оператором if, который затем разрешает выполнять разные строки программного кода.
Дополнительные пробелы, используемые для формирования отступа внутри оператора if нужны только для удобства читателя; командная оболочка их игнорирует.
Конструкция elif
К сожалению, с этим простым сценарием связано несколько проблем. Во-первых, он принимает в значении nо (нет) любой ответ за исключением yes (да). Можно усовершенствовать сценарий, воспользовавшись конструкцией elif, которая позволяет добавить второе условие, проверяемое при выполнении части else оператора if (пример 4).
Можно откорректировать предыдущий сценарий так, чтобы он выводил сообщение об ошибке, если пользователь вводит что-либо отличное от yes или nо. Для этого следует заменить ветку else веткой elif и добавить еще одно условие:
Пример 4
#!/bin/sh
echo "Сейчас утро? Ответьте yes или no"
read timeofday
if [ $timeofday = "yes" ]
then
echo "Доброе утро"
elif [ $timeofday = "no" ]; then
echo "Добрый вечер "
else
echo "Извините, $timeofday не распознается. Ответьте yes или no "
exit 1
fi
exit 0
Пример 4 очень похож на предыдущий, но теперь, если первое условие не равно true, оператор командной оболочки elif проверяет переменную снова. Если обе проверки не удачны, выводится сообщение об ошибке, и сценарий завершается со значением 1, которое в вызывающей программе можно использовать для проверки успешного выполнения сценария.
Проблема, связанная со значением переменной
Данный сценарий исправляет наиболее очевидный дефект, а более тонкая проблема остается незамеченной. Запустите новый вариант сценария, но вместо ответа на вопрос просто нажмите клавишу <Enter> . Вы получите сообщение об ошибке:
[: = : unary operator expected
Что же не так? Проблема в первой ветви оператора if. Когда проверялась переменная timeofday, она состояла из пустой строки. Следовательно, ветвь оператора if выглядела следующим образом: if [ = "yes" ] и не представляла собой верное условие. Во избежание этого следует заключить имя переменной в кавычки: if [ "$timeofday" = "yes" ]
Теперь проверка с пустой переменной будет корректной:
if [ "" = "yes" ]
Новый сценарий будет таким:
Пример 5.
#!/bin/sh
echo " Сейчас утро? Ответьте yes или no "
read timeofday
if [ "$timeofday " = "yes" ]
then
echo "Доброе утро"
elif [ "$timeofday" = "no" ]; then
echo "Добрый вечер "
else
echo "Извините, $timeofday не распознается. Ответьте yes или no "
exit 1
fi
exit 0
Этот вариант безопасен, даже если пользователь в ответ на вопрос просто нажмет клавишу <Enter>.
Примечание. Если вы хотите, чтобы команда echo не переходила на новую строку, наиболее переносимый вариант— применить команду printf (см. раздел "printf" далее) вместо команды echo. В оболочке bash для запрета перехода на новую строку допускается команда echo –n. Поэтому можно написать:
echo -n " Сейчас утро? Ответьте yes или no: "
Нужно оставлять дополнительный пробел перед закрывающими кавычками для формирования зазора перед вводимым пользователем ответом.