Настройки шрифта

| |

Фон

| | | |

 

Глава 24. Списки команд

Средством обработки последовательности из нескольких команд служат списки: \"И-списки\" и \"ИЛИ-списки\". Они эффективно могут заменить сложную последовательность вложенных if/then или даже case.

Объединение команд в цепочки

И-список

command-1 && command-2 && command-3 && ... command-n

Каждая последующая команда, в таком списке, выполняется только тогда, когда предыдущая команда вернула код завершения true (ноль). Если какая-либо из команд возвращает false (не ноль), то исполнение списка команд в этом месте завершается, т.е. следующие далее команды не выполняются.

Пример 24-1. Проверка аргументов командной строки с помощью \"И-списка\"

#!/bin/bash

# \"И-список\"



if [ ! -z \"$1\" ] && echo \"Аргумент #1 = $1\" && [ ! -z \"$2\" ] && echo \"Аргумент #2 = $2\"

then

echo \"Сценарию передано не менее 2 аргументов.\"

# Все команды в цепочке возвращают true.

else

echo \"Сценарию передано менее 2 аргументов.\"

# Одна из команд в списке вернула false.

fi

# Обратите внимание: \"if [ ! -z $1 ]\" тоже работает, но, казалось бы эквивалентный вариант

# if [ -n $1 ] -- нет. Однако, если добавить кавычки

# if [ -n \"$1\" ] то все работает. Будьте внимательны!

# Проверяемые переменные лучше всегда заключать в кавычки.

– Нет… скоро приедет мама… сестра… Может, ты позвонишь потом? Завтра? Я… прости.



Каролина повесила трубку. Сьюзан положила трубку на место и подумала, что беременность иногда мешает: она бы сейчас выпила чего-нибудь крепкого.

# То же самое, только без списка команд.

На улице уже темнело – а ведь всего пятый час. Сьюзан ненавидела короткие тусклые зимние дни и сейчас больше, чем когда-либо, скучала по долгим теплым летним вечерам. Харви Эддисон мертв. У нее не укладывалось это в голове. В сознании Сьюзан его образ раздвоился. Вот Харви Эддисон принимает ее у себя в кабинете. Может, он немного нервничал в этот момент, но она отнесла это на счет того, что ему приходится осматривать жену друга.

if [ ! -z \"$1\" ]

then

А вот перед Рождеством он стоит у них в гостиной и высокомерно говорит: «Какой прелестный маленький домик». Она возненавидела его за эти слова, он же проявил искреннее участие, когда у нее в тот вечер случился приступ. И вчера он был к ней очень добр.

echo \"Аргумент #1 = $1\"

Карьер. Арахисовое масло. Бессмыслица, с какой стороны ни посмотри.

fi

if [ ! -z \"$2\" ]

Сьюзан очень хотелось хоть как-то успокоиться, поговорить с кем-нибудь. Пять минут пятого. В Лос-Анджелесе сейчас утро, пять минут девятого. Родители уже не спят – они ранние пташки. Может быть, она застанет кого-нибудь из них дома, пока они не ушли на работу. Она просто хотела услышать их, восстановить свою веру в то, что камни, лежащие в основании ее жизни, еще целы.

then

echo \"Аргумент #2 = $2\"



echo \"Сценарию передано не менее 2 аргументов.\"

Когда Джон приехал домой и увидел вышедшую его встречать Сьюзан, он ужаснулся тому, как она осунулась от потрясения. В руках у него был номер «Ивнинг стандард».

else

– Взгляни, – сказал он, указав пальцем на первую полосу газеты.

echo \"Сценарию передано менее 2 аргументов.\"

– Да что же произошло? – спросила Сьюзан. – Я звонила Каролине, но она ничего толком не сказала.

fi

Он покачал головой:

# Получилось менее элегантно и длиннее, чем с использованием \"И-списка\".

– Мне надо выпить.



Они прошли в кухню.

exit 0

– Я сделаю, – сказала она.

Пример 24-2. Еще один пример проверки аргументов с помощью \"И-списков\"

– Я сам сделаю. А ты прочти статью.

Сьюзан развернула газету и, положив ее на стол, начала читать, не присаживаясь. Большую часть полосы занимала статья об обнаруженном властями складе взрывчатых веществ, предположительно Ирландской республиканской армии. Также на полосе, под заголовком «Загадка смерти телевизионного гинеколога», была размещена неожиданно большая фотография Харви Эддисона.

#!/bin/bash

Сама статья была очень короткой. В ней говорилось, что сегодня ранним утром Харви Эддисон, ведущий популярных телевизионных программ канала Би-би-си «Чудо рождения» и «Частная консультация», был найден мертвым в принадлежащем ему автомобиле марки «порше» в меловом карьере в Бедфордшире. В машине было обнаружено большое количество кокаина. Полиция ожидает результатов вскрытия. Харви Эддисон был женат, оставил после себя троих малолетних детей. Его вдова испытала большое потрясение и не может представить никакой информации об обнаруженных наркотиках.



Сьюзан подняла глаза на Джона, который выдавливал кубики льда из замерзшего пакета в стакан.

ARGS=1 # Ожидаемое число аргументов.

– Ты знал, что он употреблял кокаин?

E_BADARGS=65 # Код завершения, если число аргументов меньше ожидаемого.



– Нет. А что тут такого? – Он подставил стакан под краник водяного фильтра и плеснул в него воды.

test $# -ne $ARGS && echo \"Порядок использования: `basename $0` $ARGS аргумент(а)(ов)\" && exit $E_BADARGS

# Если проверка первого условия возвращает true (неверное число аргументов),

– Смерть, предположительно, наступила от передозировки наркотиков.

# то исполняется остальная часть строки, и сценарий завершается.



– Каролина что-нибудь сказала насчет этого?

# Строка ниже выполняется только тогда, когда проверка выше не проходит.

– Она сейчас не в себе. Говорила что-то об арахисовом масле – у их сына Адама аллергия на арахис.

# обратите внимание на условие \"-ne\" -- \"не равно\" (прим. перев.)

– Не вижу связи.

echo \"Сценарию передано корректное число аргументов.\"



– Я тоже.

exit 0

Джон сделал глоток виски, сел за стол и придвинул газету к себе.



– Они считают, что он совершил самоубийство?

# Проверьте код завершения сценария командой \"echo $?\".

Конечно же, с помощью И-списка можно присваивать переменным значения по-умолчанию.

– Да кто его знает.

arg1=$@ # В $arg1 записать аргументы командной строки.

– Каролина говорила, что они хорошо провели праздники и что Харви много всего собирался сделать в этом году.



[ -z \"$arg1\" ] && arg1=DEFAULT

– Для «Диджитрака» это настоящая подстава, – сказал Джон. – Не говоря уже о том, что он мне нравился. С его помощью мы зарабатывали самые большие деньги. – Он отпил еще виски.

# Записать DEFAULT, если аргументы командной строки отсутствуют.



– Насчет этих наркотиков… Невозможно же понять, насколько они сильные. Это же кот в мешке, если покупать их нелегально, у дилеров.

ИЛИ-список

– Он врач, – сказал Джон. – Он мог прописать себе все, что хотел. Скорее всего, он не связывался с криминалом – хотя я не знаю, как это работает с кокаином. И почему карьер? Поехал в карьер, чтобы нюхнуть? Зачем?

command-1 || command-2 || command-3 || ... command-n

– Может, у него была любовница и карьер был место их свиданий.

Каждая последующая команда, в таком списке, выполняется только тогда, когда предыдущая команда вернула код завершения false (не ноль). Если какая-либо из команд возвращает true (ноль), то исполнение списка команд в этом месте завершается, т.е. следующие далее команды не выполняются. Очевидно, что \"ИЛИ-списки\" имеют смысл обратный, по отношению к \"И-спискам\"

Джон задумчиво посмотрел на Сьюзан:

Пример 24-3. Комбинирование \"ИЛИ-списков\" и \"И-списков\"

#!/bin/bash

– Может быть. Они нюхают на пару, потом у него случается сердечный приступ, она пугается и сбегает? – Он покачал головой. – Неужели ты думаешь, у него не хватило бы мозгов придумать что-нибудь получше, чем карьер посреди зимы? Почему не поехать в отель?



# delete.sh, утилита удаления файлов.

– Он же часто появляется на телевидении. Может, он боялся, что его узнают, – предположила она.

# Порядок использования: delete имя_файла

Джон отхлебнул еще виски, покрутил стакан – кубики льда с дробью прошлись по стенкам. И, как вовремя вступивший музыкант, в оконное стекло постучал ветер. Затем, словно в ответ, в животе у Сьюзан шевельнулся Малыш.



Он будто почувствовал, что что-то не так.

E_BADARGS=65



«Малыш, ты читаешь мои мысли», – подумала Сьюзан.

if [ -z \"$1\" ]



then

echo \"Порядок использования: `basename $0` имя_файла\"

И Кунц, слушая этот разговор, был счастлив. Тягостное впечатление от ее электронного письма почти рассеялось. «Умница», – подумал он. Так лучше. Сьюзан, ты меня очень радуешь.

exit $E_BADARGS # Если не задано имя файла.

Я бы хотел забыть об этом письме. Будто его и не было. Как было бы хорошо не докладывать о нем мистеру Сароцини. Но я не могу.

else

А он прикажет мне наказать тебя.

file=$1 # Запомнить имя файла.

Он посмотрел на фотографию сестры Сьюзан, Кейси, которую он держал в руке. Идеально. Это накажет Сьюзан так, как ничто другое.

fi



Но Сьюзан будет признательна ему за это наказание. Ведь Тринадцатая Истина гласит: «Всякая благодарность коренится в наказании».

[ ! -f \"$file\" ] && echo \"Файл \\\"$file\\\" не найден. \\

Робкий отказ удаления несуществующего файла.\"

# И-СПИСОК, выдать сообщение об ошибке, если файл не существует.

43

# Обратите внимание: выводимое сообщение продолжается во второй строке,

Заключение коронера о смерти Харви Эддисона заняло несколько колонок в утренних газетах, вышедших во вторник, 12 марта.

# благодаря экранированию символа перевода строки.

Ванроу придерживал ультразвуковой датчик на выпуклом животе Сьюзан и улыбался.



– Киста уменьшается, – сказал он. – Ее почти не видно. Это очень хорошие новости.

[ ! -f \"$file\" ] || (rm -f $file; echo \"Файл \\\"$file\\\" удален.\")

# ИЛИ-СПИСОК, удаляет существующий файл.

Сегодня в четыре часа утра никак нельзя было подумать, что она уменьшается. Тогда Сьюзан казалось, что в животе у нее находятся раскаленные добела камни. Последние несколько недель боли у нее практически не прекращались. Кашлять и чихать было почти невозможно. Она очень плохо спала. Вот и сегодня она не выспалась и чувствовала себя разбитой.



– Тогда почему боли усиливаются? – спросила она, надевая джемпер.

# Обратите внимание на логические условия.

Майлз Ванроу сел за стол, достал авторучку и сделал несколько пометок в ее карте.

# И-СПИСОК отрабатывает по true, ИЛИ-СПИСОК -- по false.

– Эта стадия беременности редко бывает безболезненной. По большей части вам доставляет неудобство растяжение круглых связок, поддерживающих матку. Вы, по-видимому, испытываете ноющую, щемящую боль?



Сьюзан кивнула.

exit 0

– Она сильнее справа?

Списки возвращают код завершения последней выполненной команды.

– Да.

Комбинируя \"И\" и \"ИЛИ\" списки, легко \"перемудрить\" с логическими условиями, поэтому, в таких случаях может потребоваться детальная отладка.

– Резкая колющая боль?

false && true || echo false # false

Она снова кивнула.



– Боль несколько усиливается, когда вы встаете после пребывания в сидячем положении?

# Тот же результат дает

– Да.

( false && true ) || echo false # false

Ванроу улыбнулся:

# Но не эта комбинация

– Все симптомы болезненности круглых связок. Это неприятно, но абсолютно безопасно для вас и для ребенка. Через неделю-две вы почувствуете себя лучше. Есть еще жалобы?

– Боль в спине.

false && ( true || echo false ) # (нет вывода на экран)



– Это нормально.

– Чувство жжения.

# Обратите внимание на группировку и порядок вычисления условий -- слева-направо,

– Да, – сказал он, записывая.

#+ поскольку логические операции \"&&\" и \"||\" имеют равный приоритет.



– И… – Сьюзан покраснела, – похоже, геморрой.

# Если вы не уверены в своих действиях, то лучше избегать таких сложных конструкций.

– Все это в рамках нормы для текущей стадии беременности. – Доктор положил ручку и сочувственно улыбнулся. – Сьюзан, я понимаю, как много неудобств причиняют вам эти боли, но вы должны понять, что они являются доказательством тому, что вы носите здорового ребенка.



# Спасибо S.C.

– Замечательно, – сказала она и, пожав плечами, вымученно улыбнулась. – И так видно, что он здоровый. Так толкается. Наверное, вырастет футболистом и будет играть за Анг… – Она спохватилась и замолчала, затем угасшим голосом закончила: – За Швейцарию.



См. Пример A-8 и Пример 7-4, иллюстрирующие использование И/ИЛИ-списков для проверки переменных.

По лицу Ванроу пробежала тень и тут же исчезла.



– Сьюзан, я обещаю вам, что вы не будете страдать ни одного дня дольше, чем это действительно необходимо. Нас выручает, конечно, то, что с кесаревым сечением не придется дожидаться родов.

Глава 25. Массивы

– С кесаревым сечением? – перебила она.

Новейшие версии Bash поддерживают одномерные массивы. Инициализация элементов массива может быть произведена в виде: variable[xx]. Можно явно объявить массив в сценарии, с помощью директивы declare: declare -a variable. Обращаться к отдельным элементам массива можно с помощью фигурных скобок, т.е.: ${variable[xx]}.

– Да. Естественно. Из-за вашей кисты…

Сьюзан покачала головой:

Пример 25-1. Простой массив

– Нет. Я читала о естественных родах. У меня есть книги, где рожавшие женщины делятся своим опытом. Я хочу родить сама.

#!/bin/bash

Ванроу добродушно улыбнулся:



area[11]=23

– Сьюзан, я не сторонник естественных родов. Я считаю, что они изжили себя с появлением больниц и гинекологов, и, кроме того, они связаны с риском, на который я не могу пойти. Мне необходимо будет удалить остатки кисты, а это имеет смысл делать одновременно с кесаревым сечением. – Он подался вперед и сцепил перед собой длинные, поросшие волосами пальцы. – Не стоит бояться кесарева сечения. Это самый безопасный способ появления на свет – и для ребенка, и для матери.

area[13]=37

Сьюзан снова покачала головой:

area[51]=UFOs

– Я решила, что буду рожать естественным способом. Я хочу находиться в сознании, когда мой ребенок родится. Я хочу чувствовать связь с ним – или с ней.



Ванроу внимательно слушал. На его лице было написано понимание. Он сказал:

# Массивы не требуют, чтобы последовательность элементов в массиве была непрерывной.

– Даже если бы я имел иные взгляды на естественные роды, я бы все равно рекомендовал вам кесарево сечение. Вы очень ответственная и внимательная женщина, Сьюзан, вы делаете для ребенка все возможное, но вы должны избегать слишком сильной эмоциональной связи с ним. В противном случае вам будет очень тяжело с ним расстаться.



– Мне и так это будет очень тяжело.

# Некоторые элементы массива могут оставаться неинициализированными.

– Да, я понимаю. Материнский инстинкт – сильная вещь, может быть, самая сильная на земле. – Ванроу провел рукой по лбу. – Вам необходимо искать способы, как ослабить связь с ребенком, а не как усилить ее.

# \"Дыркм\" в массиве не являются ошибкой.



– Но ведь то, как ребенок родится, никак не повлияет на его будущее, – сказала Сьюзан. – Я, как и было договорено, передам его мистеру и миссис Сароцини. Но ребенок должен быть рожден с любовью, а не с равнодушием. Меня уже долгое время мучают боли. Чтобы и дальше бороться с ними, я, по крайней мере, должна быть уверена, что страдаю не напрасно и мой ребенок появится на свет, не испытав при этом боли.

echo -n \"area[11] = \"

– Повторяю, единственный способ родить ребенка без боли и травм – согласиться на кесарево сечение.

echo ${area[11]} # необходимы {фигурные скобки}



Сьюзан вдруг подумала, что сказал бы ей Харви Эддисон.

echo -n \"area[13] = \"

– Вы знаете Харви Эддисона? – сменила она тему.

echo ${area[13]}

Ванроу странно посмотрел на нее, и Сьюзан задумалась, не знает ли он, что она консультировалась у другого гинеколога. Нет, это невозможно!



– Пару раз наши дороги пересекались. А вы что, были с ним знакомы? – Доктор, казалось, задумался, затем сказал: – Ну конечно! Ваш муж работал с ним. В сегодняшней утренней газете я видел отчет о расследовании его смерти. Несчастный случай. Я думаю, коронер подошел к вопросу очень мягко.

echo \"содержимое area[51] = ${area[51]}.\"

– Почему?

– Ну, это, конечно, не мое дело, но, как практикующий врач, он должен был знать, какая доза кокаина является безопасной для здоровья, а какая – нет.



– Вы имеете в виду, что…

# Обращение к неинициализированным элементам дает пустую строку.

Ванроу вскинул брови.

echo -n \"area[43] = \"

– Что он покончил жизнь самоубийством?

– Я в этом почти не сомневаюсь. А вы считаете иначе?

echo ${area[43]}

– Я несколько раз видела его жену… вдову. – Сьюзан замолчала. Ей опять вспомнились бутерброды с арахисовым маслом. Здесь, казалось, была какая-то связь. Но какая? Полиция сбросила факт появления бутербродов в коробке с завтраком Адама со счетов, приняв версию, что их положил туда кто-нибудь из его одноклассников – в тот день бутерброды с арахисовым маслом были у нескольких детей. Они не связывали происшествие в школе со смертью гинеколога от передозировки кокаина. Звонок Харви в школу тоже не вызвал у них подозрения – он был расценен как типичное проявление родительской заботы.

echo \"(элемент area[43] -- неинициализирован)\"

– А что говорит его вдова? – спросил Ванроу.



Сьюзан плохо себя чувствовала, поэтому не стала рассказывать историю про бутерброды с арахисовым маслом. Может, Харви сошел с ума? Попытался убить сына, а затем в припадке раскаяния совершил самоубийство?

Концы явно не сходились, но Сьюзан все же не могла отделаться от мысли, что его смерть и подброшенные бутерброды связаны между собой. Для нее это было еще одним пугающим совпадением.

echo

Она попрощалась с Ванроу до следующей недели и вышла.

Стояла почти середина марта, а на то, что уже весна, не было и намека. Утро было пронизывающе-холодным, и, выйдя на улицу, Сьюзан запахнула полы своего длинного темно-синего пальто и подпоясалась.



– Как ты там, Малыш? – сказала она. – Тебе тепло?

Малыш не отозвался. «Наверное, спит», – подумала Сьюзан. Она опять не стала просить Ванроу сообщить ей пол ребенка, но по какой-то причине ей казалось, что Малыш окажется мальчиком.

# Сумма двух элементов массива, записанная в третий элемент

Приближался полдень. Машина Сьюзан была припаркована на подземной стоянке, и она за нее не беспокоилась. Несмотря на усталость, она решила прогуляться до Оксфорд-стрит и зайти в «Маркс и Спенсер».

area[5]=`expr ${area[11]} + ${area[13]}`

К тому времени, как она добралась до магазина – он оказался дальше, чем она думала, а улица была забита народом, – она совершенно выдохлась. Она купила в продуктовом отделе стакан свежего апельсинового сока и присела на скамейку возле отдела мужской одежды, затем содрала пластиковую обертку со стакана, сняла крышку и стала пить. Ее злило то, что Ванроу был не согласен с ее решением рожать без кесарева сечения. «Это мой ребенок, – упрямо думала она. – Это мое решение».

echo \"area[5] = area[11] + area[13]\"

Малыш ударил ее. Это был не обычный его пенальти за сборную Англии – это был настойчивый, нервный удар, как будто он старался привлечь ее внимание. Беспокойство Малыша передалось и ей самой.

– Люблю тебя, Малыш, – прошептала она. На глаза ей навернулись слезы. – Господи, как же я смогу кому-то тебя отдать?

echo -n \"area[5] = \"

Отдохнув несколько минут, она встала со скамьи и направилась к отделу товаров для детей. Она медленно прошла по рядам детской одежды, обмениваясь улыбками («Я тоже!») с другими находящимися там беременными женщинами. Она смотрела на то, как они выбирали одежду и потом шли к кассе, чтобы оплатить ее, и ей становилось еще грустнее. Как бы она хотела иметь возможность сделать то же!

echo ${area[5]}

Она в который раз посчитала оставшиеся дни. Сегодня 12 марта. Малыш должен родиться 26 апреля. Почти ровно полтора месяца. А потом?



У нее был телефонный номер и адрес лондонского адвоката, дамы, специализирующейся на законодательстве о суррогатном материнстве, – их прислали из интернет-справочной, куда Сьюзан посылала запрос, – но, невзирая на все ее сомнения относительно мистера Сароцини, она все никак не могла набраться духу позвонить ей.

area[6]=`expr ${area[11]} + ${area[51]}`

Она просто не могла позвонить. Они заключили с мистером Сароцини сделку, и она должна выполнить ее условия. Она должна каким-то образом избавиться от этих безумных мыслей о том, чтобы оставить ребенка себе. Через полтора месяца все закончится. Полтора месяца. И все закончится. Всего полтора месяца.

По ее лицу текли слезы. Она остановилась возле секции ярких детских комбинезонов с подходящими по цвету носочками и стала перебирать их. Затем перешла к вешалке с хлопчатобумажными костюмами. Ее внимание привлек маленький матросский костюм. Она сняла его с вешалки, повесила обратно, снова сняла и, не в силах справиться с собой, направилась к кассе.

echo \"area[6] = area[11] + area[51]\"

«Просто подарок, – убеждала она себя. – Небольшой прощальный подарок Малышу».

echo -n \"area[6] = \"

44

echo ${area[6]}

– Ну рассказывай, как она.

# Эта попытка закончится неудачей, поскольку сложение целого числа со строкой не допускается.

– Не очень хорошо. Я бы даже сказал – очень плохо.

Мистер Сароцини сидел за столом в своем кабинете в Женеве и поглаживал пальцем прижатую к уху телефонную трубку.



– Как ты оцениваешь ее шансы на выживание?