Проверка выполнения нескольких условий (выполнение нескольких команд)
Иногда необходимо выполнить оператор, только если удовлетворяется несколько условий, например if [ -f this_file ]; then if [ -f that_file ]; then if [ -f other_file ]; then echo "All files present" fi fi fi В другом случае может потребоваться, чтобы хотя бы одно условие из последовательности условий было истинным. if [ -f this_file ]; then foo="True" elif [ -f that_file ]; then foo="True" elif [ -f the_other_file ]; then foo="True" else foo="False" fi if [ "$foo" = "True" ]; then echo "One of the files exists" fi Несмотря на то, что это можно реализовать с помощью нескольких операторов if, результаты получаются очень громоздкими. В командной оболочке есть пара специальных конструкций для работы со списками условий: И-список (AND list) и ИЛИ-список (OR list). Обе они часто применяются вместе, но мы рассмотрим синтаксическую запись каждой из них отдельно. И-список Эта конструкция позволяет выполнять последовательность команд, причем каждая последующая выполняется только при успешном завершении предыдущей. Синтаксическая запись такова: оператор1 && оператор2 && оператор3 &&... Выполнение операторов начинается с самого левого, если он возвращает значение true (истина), выполняется оператор, расположенный справа от первого оператора. Выполнение продолжается до тех пор, пока очередной оператор не вернет значение false (ложь), после чего никакие операторы списка не выполняются. Операция && проверяет условие предшествующей команды. Каждый оператор выполняется независимо, позволяя соединять в одном списке множество разных команд, как показано в приведенном далее сценарии. И-список успешно обрабатывается, если все команды выполнены успешно, в противном случае его обработка заканчивается неудачно.
Пример 6. И-список В следующем сценарии выполняется обращение к файлу file_one (для проверки его наличия, и если файл не существует, он создается) и затем удаляется файл file_two. Далее И-список проверяет наличие каждого файла и между делом выводит на экран кое-какой текст. #!/bin/sh touch file_оnе 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 В примере 6 команды touch и rm гарантируют, что файл file_оnе в текущем каталоге существует, а файл file_two отсутствует. И-список выполняет команду [ -f file_one ], которая возвращает значение true, потому что файл cуществует. Поскольку предыдущий оператор завершился успешно, теперь выполняется команда echo. Она тоже завершается успешно (echo всегда возвращает true). Затем выполняется третья проверка [ -f fiie_two ]. Она возвращает значение false, т. к. файл не существует. Поскольку последняя команда вернула false, заключительная команда echo не выполняется. В результате И-список возвращает значение false, поэтому в операторе if выполняется вариант else.
ИЛИ-список Эта конструкция позволяет выполнять последовательность команд до тех пор, пока одна из них не вернет значение true, и далее не выполняется ничего более. У нее следующая синтаксическая запись: оператор1 || оператор2 || оператор3 ||... Операторы выполняются слева направо. Если очередной оператор возвращает значение false, выполняется следующий за ним оператор. Это продолжается до тех пор, пока очередной оператор не вернет значение true, после этого никакие операторы уже не выполняются. ИЛИ-список очень похож на И-список, за исключением того, что правило для выполнения следующего оператора - выполнение предыдущего оператора со значением false.
Пример 7. #!/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 }
Оператор выбора case
Оператор case немного сложнее уже рассмотренных ранее операторов. Формат записи оператора следующий: саsе переменная in образец [ | образец]...) операторы;; образец [ | образец]...) операторы;;
esас Конструкция оператора case позволяет сопоставлять содержимое переменной с образцами и затем выполнять разные операторы в зависимости от того, с каким образцом найдено соответствие. Это гораздо проще, чем проверять несколько условий, применяемых во множественных операторах if, elif и else.
Каждая ветвь с образцами завершается удвоенным символом точка с запятой (;;). В каждой ветви оператора case можно поместить несколько операторов, поэтому сдвоенная точка с запятой необходима для отметки завершения очередного оператора и начала следующей ветви с новым образцом в операторе case.
Оператор цикла for Цикл for предназначен для обработки в цикле ряда значений, которые могут представлять собой любое множество строк. Строки могут быть просто перечислены в программе или, что бывает чаще, представлять собой результат выполненной командной оболочкой подстановки имен файлов. Синтаксис оператора цикла: for переменная in значения do операторы done
Пример 8. #!/bin/sh for foo in bar dog 413 do echo $foo done exit 0 В результате будет получен следующий вывод: bar dog
Что произойдет, если изменить первую строку с for foo in bar dog 413 на for foo in "bar dog 413"? Напоминаем, что вставка кавычек заставляет командную оболочку считать все, что находится между ними, единой строкой. Это один из способов сохранения пробелов в переменной. Как работает цикл В данном примере создается переменная foo и ей в каждом проходе цикла for присваиваются разные значения. Поскольку оболочка считает по умолчанию все переменные строковыми, применять строку 413 так же допустимо, как и строку dog.
Пример 9. Применение цикла for с метасимволами Цикл for обычно используется в командной оболочке вместе с метасимволами или знаками подстановки для имен файлов. Это означает применение метасимвола для строковых значений и предоставление оболочке возможности подставлять все значения на этапе выполнения. Этот прием использован в первом примере first. В сценарии применялись средства подстановки командной оболочки — символ * для подстановки имен всех файлов из текущего каталога. Каждое из этих имен по очереди используется в качестве значения переменной $file внутри цикла for. Рассмотрим еще один пример подстановки с помощью метасимвола. Допустим, нужно вывести на экран все имена файлов сценариев в текущем каталоге, начинающиеся с буквы "f", и имена всех сценариев заканчиваются символами.sh. Это можно сделать следующим образом:
#!/bin/sh for file in $(ls f*.sh); do echo $file done echo $file exit 0
В примере показано применение синтаксической конструкции $(команда). Обычно список параметров для цикла for задается выводом команды, включенной в конструкцию $(). Командная оболочка раскрывает f*.sh, подставляя имена всех файлов, соответствующих данному шаблону. Все подстановки переменных в сценариях командной оболочки делаются во время выполнения сценария, а не в процессе их написания, поэтому все синтаксические ошибки в объявлениях переменных обнаруживаются только на этапе выполнения, как было показано ранее, когда мы заключали в кавычки пустые переменные.
Цикл while Поскольку по умолчанию командная оболочка считает все значения строками, оператор for хорош для циклической обработки наборов строк, но не слишком удобен, если не известно заранее, сколько раз придется его выполнить. Если нужно повторить выполнение последовательности команд, но заранее не известно, сколько раз следует их выполнить, применяется цикл while со следующей синтаксической записью: while условие do операторы done
Пример 10. Программа проверки паролей. #!/bin/sh echo "Enter password" read trythis while [ "$trythis"! = "secret" ]; do echo "Sorry, try again" read trythis done exit 0 Следующие строки - пример вывода данного сценария: Enter password password Sorry, try again secret $ Это небезопасный способ выяснения пароля, но он вполне подходит для демонстрации применения цикла while. Операторы, находящиеся между операторами do и done, выполняются бесконечное число раз до тех пор, пока условие остается истинным (true). В данном случае проверяетcя, равно ли значение переменной trythis строке secret. Цикл будет выполняться, пока $trythis не равно secret. Затем выполнение сценария продолжится с оператора, следующего сразу за оператором done.
Цикл until У цикла until следующая синтаксическая запись: until условие do операторы done Запись очень похожа на синтаксическую запись цикла while, но с обратным проверяемым условием. Другими словами, цикл продолжает выполняться, пока условие не станет истинным (true). Пример 11. Вычисление суммы целых чисел, вводимых с клавиатуры. Признак окончания ввода – число 0. #!/bin/sh sum=0 read num until [ $num –eq 0 ]; do sum=$((sum+num)) read num done echo $sum exit 0 Как правило, если нужно выполнить цикл хотя бы один раз, применяют цикл while; если такой необходимости нет, используют цикл until. Функции В командной оболочке можно определять функции, используемые для структурирования кода. Как альтернативу можно использовать разбиение большого сценария на много маленьких, каждый из которых выполняет небольшую задачу. У этого подхода есть несколько недостатков: выполнение вложенного в сценарий другого сценария будет гораздо медленнее, чем выполнение функции и значительно труднее возвращать результаты.
Для определения функции в командной оболочке просто введите ее имя и следом за ним пустые круглые скобки, а операторы тела функции заключите в фигурные скобки. Имя_функции () { операторы } Пример 12. Простая функция Начнем с действительно простой функции. #!/bin/sh foo () { echo "Function foo is executing" } echo "script starting" foo echo "script ended" exit 0
Cценарий выведет на экран следующий текст: script starting Function foo is executing script ended
Данный сценарий начинает выполняться с первой строки. Когда он находит конструкцию foo () {, он знает, что здесь дается определение функции, названной foo. Он запоминает ссылку на функцию и foo продолжает выполнение после обнаружения скобки }. Когда выполняется строка с единственным именем foo, командная оболочка знает, что нужно выполнить предварительно определенную функцию. Когда функция завершится, выполнение сценария продолжится в строке, следующей за вызовом функции foo. Всегда необходимо определить функцию прежде, чем ее запускать, что похоже на стиль, принятый в языке программирования Pascal, когда вызову функции предшествует ее определение, за исключением того, что в командной оболочке нет опережающего объявления (forward) функции. Это ограничение не создает проблем, потому что все сценарии выполняются с первой строки, поэтому если просто поместить все определения функций перед первым вызовом любой функции, все функции окажутся определенными до того, как будут вызваны. Когда функция вызывается, позиционные параметры сценария $*, $#, $1, $2 и т. д. заменяются параметрами функции. Именно так считываются параметры, передаваемые функции. Когда функция завершится, они восстановят свои прежние значения. Функция возвращает числовые значения с помощью команды return. Обычный способ возврата функцией строковых значений — сохранение строки в переменной, которую можно использовать после завершения функции. Другой способ — вывести строку с помощью команды echo и перехватить результат, как показано далее. foo () { echo JAY;} … result="$(foo)" В функциях командной оболочки можно объявлять локальные переменные с помощью ключевого слова local. В этом случае переменная действительна только в пределах функции. В других случаях функция может обращаться к переменным командной оболочки, у которых глобальная область действия. Если у локальной переменной то же имя, что и у глобальной, в пределах функции локальная переменная перекрывает глобальную. Для того чтобы убедиться в этом на практике, можно выполнить следующий сценарий. #!/bin/sh sample_text="global variable" foo () { local sample_text="local variable" echo "Function foo is executing" echo $sample_text } echo "script starting" echo $sample_text foo echo "script ended" echo $sample_text exit 0 При отсутствии команды return, задающей возвращаемое значение, функция возвращает статус завершения последней выполненной команды. В следующем сценарии, my_name, показано, как в функцию передаются, параметры и как функции могут вернуть логический результат true или false. Этот сценарий можно вызвать с параметром, задающим имя, которое необходимо использовать в вопросе. 1. После заголовка командной оболочки определите функцию yes_or_no #!/bin/sh yes_or_no () { echo "Is your name $*? " while true do echo -n "Enter yes or no: " read x case "$x" in у | yes) return 0;; n | no) return 1;; *) echo "Answer yes or no" esac done } 2. Далее начинается основная часть программы. echo "Original parameters are $*" if yes_or_no "$1" then echo "Hi $1, nice name" else echo "Never mind" fi exit 0 Типичный вывод этого сценария может выглядеть следующим образом: $./mу_nаmе Rick Neil Original parameters are Rick Neil Is your name Rick? Enter yes or no: yes Hi Rick, nice name $ Как работает сценарий Когда сценарий начинает выполняться, функция определена, но еще не выполняется. В операторе if сценарий вызывает функцию yes_or_nо, передавая ей оставшуюся часть строки как параметры после замены $1 первым параметром исходного сценария строкой Rick. Функция использует эти параметры, в данный момент хранящиеся в позиционных параметрах $1, $2 и т. д., и возвращает значение в вызывающую программу. В зависимости от возвращенного функцией значения конструкция if выполняет один из операторов.
Команды В сценариях командной оболочки можно выполнять два сорта команд. Как уже упоминалось, существуют "обычные" команды, которые могут выполняться и из командной строки (называемые внешними командами), и встроенные команды (называемые внутренними командами). Внутренние команды реализованы внутри оболочки и не могут вызываться как внешние программы. Но большинство внутренних команд представлено и в виде автономных программ, это условие - часть требований стандарта POSIX. Обычно не важно, команда внешняя или внутренняя, за исключением того, что внутренние команды выполняются быстрее. В этом разделе представлены основные команды, как внутренние, так и внешние, которые используются при написании сценариев. Команда break Команда break используется для выхода из циклов for, while и until до того, как будет удовлетворено управляющее условие. Пример 13 #!/bin/sh rm -rf fred* echo > fred1 echo > fred2 mkdir fred3 echo > fred4 for file in fred* do if [ -d "$file" ]; then break; fi done echo first directory starting fred was $file rm -rf fred* exit 0 Команда continue Как и одноименный оператор языка С, эта команда заставляет охватывающий ее цикл for, while нли until начать новый проход или следующую итерацию. При этом переменная цикла принимает следующее значение в списке. Пример 14 #!/bin/sh rm -rf fred* echo > fred1 echo > fred2 mkdir fred3 echo > fred4 for file in fred* do if [ -d "$file" ]; then echo "skipping directory $file" continue fi echo file is $file done rm -rf fred* exit 0 Команда continue может принимать в качестве необязательного параметра номер прохода охватывающего цикла, с которого следует возобновить выполнение цикла. Таким образом, можно иногда выскочить из вложенных циклов. Данный параметр редко применяется, т. к. он часто сильно затрудняет понимание сценариев. Например, for х in 1 2 3 do echo before $x continue 1 echo after $x done У приведенного фрагмента будет следующий вывод: before 1 before 2 before 3
Команды echo и printf При использовании команды echo возникает общая проблема - удаление символа перехода на новую строку. В ОС Linux общепринятый метод - echo -n "string to output" Printf Команда printf есть только в современных командных оболочках. Группа Х/Ореп полагает, что ее следует применять вместо команды echo для генерации форматированного вывода. У команды printf следующая синтаксическая запись.
printf "строка формата" параметр1 параметр2...
Строка формата очень похожа с некоторыми ограничениями на применяемую в языках программирования С и C++. Главным образом не поддерживаются числа с плавающей точкой, поскольку все арифметические операции в командной оболочке выполняются над целыми числами. Строка формата состоит из произвольной комбинации литеральных символов, escape-последовательностей и спецификаторов преобразования. Все символы строки формата, отличающиеся от \ и %, отображаются на экране при выводе. В табл. 3 приведены поддерживаемые командой escape-последовательности.
Таблица 3. Некоторые escape-последовательности
Спецификатор преобразования состоит из символа %, за которым следует символ преобразования. Основные варианты преобразований перечислены в табл. 4.
Таблица 4 Спецификаторы преобразования
Строка формата используется для интерпретации остальных параметров команды и вывода результата, как показано в следующем примере: $ printf "%s\n" hello hello $ printf "%s %d\t%s" "Hi There" 15 people Hi There 15 people Обратите внимание на то, что для превращения строки Hi There в единый параметр ее нужно заключить в кавычки ("").
Команда return Команда return служит для возврата значений из функций, как уже упоминалось ранее при обсуждении функций. Команда принимает один числовой параметр, который становится доступен в сценарии, вызывающем функцию. Если параметр не задан, команда return по умолчанию возвращает код завершения последней команды.
Команда shift Команда shift сдвигает все переменные-параметры на одну позицию назад, так что параметр $2 становится параметром $1, параметр $3 - $2 и т. д. Предыдущее значение параметра $1 отбрасывается, а значение параметра $0 остается неизменным. Если в вызове команды shift задан числовой параметр, параметры сдвигаются на указанное количество позиций. Остальные переменные $* и $# также изменяются в связи с новой расстановкой переменных-параметров. Команда shift часто полезна при поочередном просмотре параметров, переданных в сценарий, и если вашему сценарию требуется 10 и более параметров, вам понадобится команда shift для обращения к 10-му параметру и следующим за ним. Например, вы можете просмотреть все позиционные параметры: #!/bin/sh while [ "S1"!= ""]; do echo "$1" shift done exit 0
Команда stat Команда stat предназначена для получения информации об указанном файле и о свойствах файловой системы на носителе, на котором хранится указанный файл. Примеры использования команды. Команда stat res где res – имя файла, выводит на экран всю информацию о файле с именем res и о владельце этого файла. Команда stat –f res где res – имя файла, выводит на экран всю информацию о файловой системе на диске, на котором хранится файл с именем res. Для получения доступа к отдельным полям информации о файле или файловой системе к приведенным выше командам добавляется ключ –с и параметр, определяющий поле. Например, для получения размера файла в байтах должен быть указан ключ %s и команда stat записывается в виде stat res –c %s Список ключей команды stat можно получить с помощью команды stat --help
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|