автордың кітабын онлайн тегін оқу Идиомы bash
Переводчик Л. Киселева
Карл Олбинг, Джей Пи Фоссен
Идиомы bash. — СПб.: Питер, 2023.
ISBN 978-5-4461-2307-0
© ООО Издательство "Питер", 2023
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.
Вступление
Вот как словарь Уэбстера определяет термин идиома:1
1. Специфический оборот речи, употребляющийся как единое целое, значение которого не определяется значением входящих в него слов (как, например, оборот «в подвешенном состоянии», означающий «неопределенность»). В данном обороте может иметь место нетипичное грамматическое использование слов (например, «дать дорогу»).
2а. Язык, свойственный народу, географической области, сообществу или классу, диалект.
2б. Синтаксическая, грамматическая или структурная форма, характерная для языка.
3. Стиль или форма художественного выражения, характерные для человека, периода или движения, средства или инструмента.
Почему для книги выбрано название «Идиомы bash»? Для простоты. Или, если хотите, чтобы было понятнее. В этой книге «простота» — синоним «понятности». Мы не собираемся убеждать вас в важности удобочитаемости: если это не первая книга по программированию, которую вы читаете, значит, уже должны это понимать. Удобочитаемость означает простоту чтения и понимания кода, особенно если он написан не вами. Не менее важно научиться писать код так, чтобы в будущем вы или кто-то другой смогли его понять. Очевидно, что эти аспекты являются разными сторонами одной медали, поэтому мы рассмотрим и идиомы, которые следует использовать, и такие, которых следует избегать.
Между нами говоря, мы считаем bash языком «управления». Для сложной обработки данных он малопригоден: ее можно реализовать, но код получится слишком сложным. Однако, если все инструменты, необходимые для обработки данных, уже имеются и требуется лишь «склеить» их, то bash подойдет на эту роль как нельзя лучше.
Если мы собираемся использовать bash только для управления, то зачем беспокоиться об идиомах или «структурной форме» языка? Программы развиваются, возможности ширятся, ситуация меняется, но нет ничего более постоянного, чем временное. Рано или поздно кому-то придется прочитать ваш код, понять его и изменить. Если он написан с использованием непонятных идиом, то сделать это будет намного сложнее.
Во многих отношениях bash не похож на другие языки. У него богатая история (некоторые могут сказать «багаж»), и есть причины, почему он выглядит и работает определенным образом. Мы не будем много говорить об этом. Если вам интересна эта тема, обратитесь к нашей книге «bash Cookbook»2. Сценарии командной оболочки «управляют миром», по крайней мере в мирах Unix и Linux (а Linux фактически управляет облачным миром), причем подавляющее большинство этих сценариев написаны на bash. Поддержание обратной совместимости с самыми первыми командными оболочками Unix часто критически важно, но накладывает некоторые... ограничения.
Теперь о «диалектах». Наиболее важным, особенно для обратной совместимости, является стандарт POSIX. Об этом тоже не будем много говорить, в конце концов эта книга посвящена идиомам bash, а не POSIX. Появление других диалектов возможно, когда программисты пишут код на bash в стиле другого известного им языка. Однако поток, имеющий смысл в C, может показаться бессвязным в bash.
Итак, в этой книге мы намерены продемонстрировать «стиль или форму... выражения, характерную» для bash (в духе третьего определения в словаре Уэбстера). Программисты на Python называют свой стиль pythonic. А мы бы хотели в этой книге показать стиль bashy.
К концу книги читатель приобретет следующие знания и навыки:
● научится писать полезный, гибкий, удобочитаемый и... стильный код на bash;
● узнает, как расшифровываются идиомы bash, такие как ${MAKEMELC,,} и ${PATHNAME##*/};
● освоит приемы, экономящие время и обеспечивающие согласованность при автоматизации задач;
● сможет удивить и впечатлить коллег идиомами bash;
● узнает, как идиомы bash помогают сделать код чистым и лаконичным.
Запуск bash
Мы предполагаем, что вы уже имеете опыт программирования на bash и нет нужды рассказывать, где его найти или как установить. Конечно, bash есть почти во всех дистрибутивах Linux, и он уже установлен по умолчанию или может быть установлен практически в любой операционной системе. Получить версию для Windows можно с помощью Git for Windows3 подсистемы Windows для Linux (Windows Subsystem for Linux, WSL) или другими способами.
bash на Mac
Обратите внимание на версию bash, которая по умолчанию устанавливается в Mac: она довольно старая и не поддерживает многие новые идиомы версий 4.0 и выше. Более свежую версию можно получить с помощью MacPorts, Homebrew или Fink. По информации от Apple4, проблема в том, что новые версии bash используют GPLv3, что является проблемой для macOS.
Apple также сообщает, что macOS Catalina и более новые версии будут использовать Zsh в качестве интерактивной оболочки и оболочки входа по умолчанию. Zsh в значительной мере совместима с bash, но некоторые примеры в этой книге потребуют изменений. Командная оболочка bash на компьютерах Mac не исчезнет (по крайней мере, пока), причем использование Zsh в качестве оболочки по умолчанию не повлияет на строку «shebang» (см. раздел «Shebang!» в главе 9), но имейте в виду, что если не обновить версию bash, вы застрянете в каменном веке.
Мы отметили примеры сценариев, несовместимые с Zsh, комментарием: «Не работает в Zsh 5.4.2!».
bash в контейнерах
Будьте осторожны, используя Docker и другие создатели контейнеров, где /bin/sh ссылается не на bash, а /bin/bash может вообще не существовать! Это особенно актуально для ограниченных окружений, включая системы интернета вещей и промышленные контроллеры.
/bin/sh может ссылаться на bash (согласно POSIX), но также на Ash, Dash, BusyBox (которым чаще всего является Dash) или что-то еще. Будьте внимательны (см. раздел «Shebang!» в главе 9) и убедитесь, что bash действительно установлен, или придерживайтесь стандарта POSIX и избегайте «башизмов».
Управление версиями
Очень надеемся, что вы используете какую-либо систему управления версиями. Если да, то можете пропустить этот абзац. Если нет, то внедрите их в свою работу, прежде чем продолжать чтение. Мы посвятили этому вопросу целое приложение в «bash Cookbook»5, но вообще в интернете можно найти огромный объем информации о таких системах, в том числе от одного из авторов этой книги6.
Hello World
Во многих трудах нужно добраться до конца главы 1, 2 или даже 3, прежде чем вы узнаете, как вывести на экран «Hello World». Мы же перейдем к этому вопросу немедленно! Впрочем, поскольку вы уже писали код на bash и храните его в системе управления версиями (верно?), то говорить об echo 'Hello, World' было бы довольно глупо, а потому и не будем. Упс.
Условные обозначения
В этой книге используются следующие условные обозначения.
Курсив
Курсивом выделены новые термины или важные понятия.
Моноширинный шрифт
Обозначает листинги программ, а также используется внутри абзацев для переменных, функций, баз данных, типов данных, переменных среды, операторов и ключевых слов, имен файлов и их расширений.
Моноширинный полужирный шрифт
Обозначает элементы, которые пользователь должен ввести самостоятельно.
Моноширинный курсив
Обозначает текст, который должен быть заменен значениями, введенными пользователем или определяемыми контекстом.
Шрифт без засечек
Используется для обозначения URL, адресов электронной почты, названий кнопок и других элементов интерфейса, а также каталогов.
Этот рисунок указывает на совет или предложение.
Этот рисунок указывает на общее примечание.
Этот рисунок указывает на предупреждение.
Использование исходного кода примеров
Вспомогательные материалы (примеры кода, упражнения и т.д.) доступны для загрузки по адресу: https://github.com/vossenjp/bashidioms-examples. Если у вас возникнут вопросы технического характера по использованию примеров кода, направляйте их по электронной почте на адрес bookquestions@oreilly.com.
В общем случае все примеры кода из книги вы можете использовать в своих программах и в документации. Вам не нужно обращаться в издательство за разрешением, если вы не собираетесь воспроизводить существенные части программного кода. Если вы разрабатываете программу и используете в ней несколько фрагментов кода из книги, вам не нужно обращаться за разрешением. Но для продажи или распространения примеров из книги вам потребуется разрешение от издательства O’Reilly. Вы можете отвечать на вопросы, цитируя данную книгу или примеры из нее, но для включения существенных объемов программного кода из книги в документацию вашего продукта потребуется разрешение.
Мы рекомендуем, но не требуем добавлять ссылку на первоисточник при цитировании. Под ссылкой на первоисточник мы подразумеваем указание авторов, издательства и ISBN.
За получением разрешения на использование значительных объемов программного кода из книги обращайтесь по адресу permissions@oreilly.com.
Очень надеемся, что вы используете какую-либо систему управления версиями. Если да, то можете пропустить этот абзац. Если нет, то внедрите их в свою работу, прежде чем продолжать чтение. Мы посвятили этому вопросу целое приложение в «bash Cookbook»5, но вообще в интернете можно найти огромный объем информации о таких системах, в том числе от одного из авторов этой книги6.
Во многих отношениях bash не похож на другие языки. У него богатая история (некоторые могут сказать «багаж»), и есть причины, почему он выглядит и работает определенным образом. Мы не будем много говорить об этом. Если вам интересна эта тема, обратитесь к нашей книге «bash Cookbook»2. Сценарии командной оболочки «управляют миром», по крайней мере в мирах Unix и Linux (а Linux фактически управляет облачным миром), причем подавляющее большинство этих сценариев написаны на bash. Поддержание обратной совместимости с самыми первыми командными оболочками Unix часто критически важно, но накладывает некоторые... ограничения.
https://oreil.ly/pgx8b.
https://gitforwindows.org/.
https://learning.oreilly.com/library/view/bash-cookbook-2nd/9781491975329/.
https://github.com/vossenjp/bashidioms-examples/blob/main/bcb2-appd.pdf.
https://oreil.ly/2PZRm.
https://oreil.ly/fPHy8.
Мы предполагаем, что вы уже имеете опыт программирования на bash и нет нужды рассказывать, где его найти или как установить. Конечно, bash есть почти во всех дистрибутивах Linux, и он уже установлен по умолчанию или может быть установлен практически в любой операционной системе. Получить версию для Windows можно с помощью Git for Windows3 подсистемы Windows для Linux (Windows Subsystem for Linux, WSL) или другими способами.
Вот как словарь Уэбстера определяет термин идиома:1
Обратите внимание на версию bash, которая по умолчанию устанавливается в Mac: она довольно старая и не поддерживает многие новые идиомы версий 4.0 и выше. Более свежую версию можно получить с помощью MacPorts, Homebrew или Fink. По информации от Apple4, проблема в том, что новые версии bash используют GPLv3, что является проблемой для macOS.
Очень надеемся, что вы используете какую-либо систему управления версиями. Если да, то можете пропустить этот абзац. Если нет, то внедрите их в свою работу, прежде чем продолжать чтение. Мы посвятили этому вопросу целое приложение в «bash Cookbook»5, но вообще в интернете можно найти огромный объем информации о таких системах, в том числе от одного из авторов этой книги6.
Благодарности
Bash
Спасибо GNU Software Foundation и Брайану Фоксу (Brian Fox) за создание bash. Благодарим также Чета Рэми (Chet Ramey), поддерживающего и совершенствующего bash, начиная с версии 1.14, которая вышла в первой половине 1990-х. Все вы дали нам отличный инструмент.
Рецензентам
Большое спасибо рецензентам: Дугу Макилрою (Doug McIlroy), Яну Миеллу (Ian Miell), Кертису Олду (Curtis Old) и Полу Тронконе (Paul Troncone), которые помогли значительно улучшить книгу! Все они дали ценные отзывы, а в некоторых случаях предложили альтернативные решения, указав на проблемы, которые мы упустили из виду. Если в этой книге есть ошибки или упущения, то это не их, а наша вина.
O’Reilly
Спасибо всем сотрудникам издательства O’Reilly, без которых эта книга не появилась бы на свет, а если и появилась бы, то по содержанию и оформлению была бы беднее.
Спасибо Майку Лукидесу (Mike Loukides) за оригинальную идею и то, что предложил и доверил реализовать ее нам. Спасибо Сюзанне «Зан» МакКуэйд (Suzanne «Zan» McQuade), что помогла воплотить идею в жизнь. Огромная благодарность Николь Таше (Nicole Taché) и Кристен Браун (Kristen Brown) за правки и то, что терпели нас в ходе долгой работы над книгой и ее подготовки к печати. Особое спасибо Нику Адамсу (Nick Adams) из Tools за исправление наших многочисленных (и порой вопиющих) ошибок в AsciiDoc, а также помощь в вопросах, не связанных с набором. Спасибо литературному редактору Ким Сандовал (Kim Sandoval), составителю индекса Шерил Ленсер (Cheryl Lenser), корректору Лиз Уилер (Liz Wheeler), дизайнерам Дэвиду Футато (David Futato) и Карен Монтгомери (Karen Montgomery), а также другим сотрудникам O’Reilly.
От Карла
Спасибо Джей Пи за его работу, внимание к деталям и готовность к сотрудничеству. Спасибо всем сотрудникам O’Reilly за помощь в издании этой книги.
Эту книгу я посвящаю моей супруге Синтии, которая мирилась с моими писательскими амбициями и достаточно убедительно делала вид, что ей интересно, о чем я пишу. Моя работа над этой книгой направлена, как говорят в Бетельском университете, во славу Божию и на благо моих ближних.
От Джей Пи
Спасибо Карлу за его работу; похоже, нам снова удалось уложиться в график. Спасибо Майку за то, что опять привел все в движение, и Николь за ее труд, а также терпеливое отношение к нашим работе, жизни и неумению правильно распределять время.
Эту книгу я посвящаю моей супруге Карен — «исполнительному вице-президенту», отвечающему за все. Спасибо за твою невероятную поддержку, терпение и понимание, без тебя я бы не состоялся в жизни. Наконец, спасибо Кейт и Сэму за то, что нормально воспринимали мой ответ: «Если вы не истекаете кровью и не горите, то не мешайте: я занят книгой».
От издательства
Ваши замечания, предложения, вопросы отправляйте по адресу comp@piter.com (издательство «Питер», компьютерная редакция).
Мы будем рады узнать ваше мнение!
На веб-сайте издательства www.piter.com вы найдете подробную информацию о наших книгах.
Глава 1. Идиома «большого» if
Знакомство с идиомами bash мы начнем с конструкции, которая позволяет делать то же самое, что и привычные операторы if/then/else, но имеет более компактный синтаксис. Идиоматическая конструкция, которую мы рассмотрим в этой главе, не только дает реальные преимущества (в основном — краткость), но также таит некоторые ловушки. Кроме того, не зная этой идиомы bash, можно вообще не понять смысл кода.
Взгляните на фрагмент кода:
[[ -n "$DIR" ]] && cd "$DIR"
Как вы думаете, похож он на оператор if? Знакомые с bash заметят, что функционально это тождественно оператору if, даже при том, что ключевое слово if отсутствует.
Давайте разберем, что делает этот код.
«Большой» if
Прежде чем объяснить эту идиому, рассмотрим похожий, но более простой пример:
cd tmp && rm scratchfile
По сути, это тоже оператор if. Если команда cd выполнится успешно, то выполнится и команда rm. «Идиома» здесь — это использование для разделения команд пары амперсандов (&&), которая обычно читается как «И».
На уроках логики и философии учат правилу: выражение «А И Б» истинно тогда и только тогда, когда оба условия, А и Б, истинны. Следовательно, если А ложно, то нет необходимости даже рассматривать Б. Например, возьмем такое выражение: «У меня есть собака, И у меня есть кошка». Если у меня нет собаки, то это составное выражение неверно, независимо от наличия у меня кошки.
Применим это правило в bash. Напомним, что основная функция bash — выполнять команды. В первой части нашего примера выполняется команда cd. В соответствии с логикой, если эта первая команда потерпела неудачу, то bash не будет выполнять вторую команду rm.
Оператор && позволяет использовать логическое «И». На самом деле bash не выполняет логическую операцию с двумя результатами (в C/C++ была бы другая логика при таком же синтаксисе). Эта идиома просто обеспечивает условное выполнение второй команды, которая не запускается, если первая команда завершилась с ошибкой.
Теперь вернемся к исходному примеру:
[[ -n "$DIR" ]] && cd "$DIR"
Стал ли он теперь более понятным? Первое выражение проверяет, отличается ли длина значения переменной DIR от нуля. Если переменная имеет некоторое значение, то есть длина этого значения отлична от нуля, то команда cd попытается перейти в каталог, имя которого соответствует значению DIR.
То же самое можно было бы записать, явно использовав оператор if:
if [[ -n "$DIR" ]]; then
cd "$DIR"
fi
Для тех, кто плохо знаком с bash, этот последний фрагмент, безусловно, выглядит понятнее. Но внутри ветки then выполняется очень мало действий, только команда cd, поэтому такой синтаксис условного выполнения кажется излишне громоздким. Вам придется решать, какой синтаксис использовать, исходя из того, кто будет читать ваш код и насколько высока вероятность добавления других команд в ветку then. В следующих разделах мы рассмотрим несколько возможных вариантов.
Справка bash
Команда help в bash служит отличным источником информации о встроенных командах, а команда help test дает ценные подсказки о выражениях проверки условий, таких как -n. Также можно заглянуть в справочное руководство man bash, тогда придется отыскать раздел Conditional expressions (условные выражения). Но справочник man — очень объемный, а команда help дает короткие и содержательные подсказки. Если вы не уверены, встроена ли та или иная команда в bash, то просто передайте ее команде help или введите: type -a команда.
Если бы вы знали, что help test расскажет вам о значении -n, то, может, и не купили бы эту книгу. И еще один тонкий момент: попробуйте команду help [. Пожалуйста.
Или ELSE...
Существует похожая идиома, основанная на использовании символов || для разделения двух элементов в команде bash. Эта пара символов читается как «ИЛИ»: вторая часть команды будет выполнена, только если первая закончится неудачей. Такой образ действий напоминает логическое «ИЛИ», например: А ИЛИ Б. Все выражение истинно, если истинна хотя бы одна из его частей, А или Б. Иными словами, если А истинно, то не имеет значения, истинно ли Б. Например, рассмотрим такое выражение: «У меня есть собака ИЛИ кошка». Если у меня действительно есть собака, то это выражение истинно, независимо от наличия кошки.
Применим это правило в bash:
[[ -z "$DIR" ]] || cd "$DIR"
Сможете объяснить, как работает это выражение? Если значение переменной имеет нулевую длину, то первая часть будет оценена как «истинная» и вторая половина выполняться не будет, то есть команда cd не будет выполнена. Но если значение $DIR имеет ненулевую длину, то проверка вернет «ложь» и команда cd выполнится.
Эту строку на языке bash можно прочитать так: «Либо $DIR имеет нулевую длину, либо попытаться перейти в этот каталог».
Запись тех же действий с использованием оператора if выглядит немного странно, потому что ветка then — пустая. Код после || похож на ветку else:
if [[ -z "$DIR" ]]; then
:
else
cd "$DIR"
fi
Двоеточие (:) — это пустая инструкция, которая ничего не делает.
Итак, две команды, разделенные символами &&, похожи на оператор if и его ветку then; две команды, разделенные символами ||, похожи на оператор if и его ветку else.
Выполняем несколько команд
Если требуется выполнить несколько команд после пары символов ||, как в ветке else, или после &&, как в ветке then, то нередко допускаются ошибки. Например, может возникнуть соблазн написать такой код:
# Внимание: этот код работает не так, как можно предположить!
cd /tmp || echo "cd to /tmp failed." ; exit
Оператор «ИЛИ» говорит нам, что в случае сбоя cd выполнится команда echo, которая сообщит пользователю, что cd потерпела неудачу. Но вот в чем загвоздка: exit выполнится в любом случае. Вы этого не ожидали, верно?
Интерпретируйте точку с запятой (;) как эквивалент перевода строки, и все сразу станет на свои места (и выяснится, что это не то, чего вы хотели):
cd /tmp || echo "cd to /tmp failed."
exit
Можно ли добиться желаемого результата? Да, для этого следует сгруппировать echo и exit в одно предложение справа от «ИЛИ», например:
# Или cd выполнится успешно, или сценарий завершится с сообщением об ошибке
cd /tmp || { echo "cd to /tmp failed." ; exit ; }
Фигурные скобки в bash используются для определения составных команд, то есть для группировки инструкций. Возможно, вы видели нечто подобное с использованием круглых скобок, но инструкции, заключенные в круглые скобки, выполняются в подоболочке, также называемой дочерним процессом. Это связано с ненужными в данном случае расходами ресурсов, к тому же выход по команде exit произойдет из подоболочки, что не даст желаемого результата.
Завершение составных команд
Синтаксис bash требует в обязательном порядке завершать составные команды точкой с запятой или переводом строки перед закрывающей фигурной скобкой. Если используется точка с запятой, то она должна отделяться пробелом от закрывающей фигурной скобки, чтобы интерпретатор распознал ее как служебный символ (иначе она будет перепутана с закрывающей фигурной скобкой синтаксиса переменных оболочки, например ${VAR}). Вот почему предыдущий пример заканчивается, казалось бы, лишней точкой с запятой: { echo "..." ; exit ; }. При использовании перевода строки завершающая точка с запятой не нужна:
# Или cd выполнится успешно, или сценарий завершится с сообщением об ошибке
cd /tmp || { echo "cd to /tmp failed." ; exit
}
но такой код воспринимается неоднозначно. Закрывающая фигурная скобка у левого края будет выглядеть странно; если же добавить отступ, как в примере выше, то такая строка кажется голой. Мы рекомендуем использовать дополнительную точку с запятой, не забывая о пробеле между ней и закрывающей фигурной скобкой.
Еще о случае нескольких команд
Что, если требуется реализовать более сложную логику, например с несколькими конструкциями «И» и «ИЛИ»? Как их объединить? Рассмотрим следующую строку кода:
[ -n "$DIR" ] && [ -d "$DIR" ] && cd "$DIR" || exit 4
Если переменная DIR — непустая и существует каталог с таким именем, то cd выполнит переход в этот каталог; иначе сценарий завершится с кодом 4. Эта группа команд делает именно то, что можно было бы ожидать, но правильно ли вы понимаете логику?
При взгляде на этот пример можно подумать, что оператор && имеет более высокий приоритет, чем ||, но в действительности это не так. Они выполняются в порядке следования слева направо. В bash операторы && и || имеют одинаковый приоритет и являются левоассоциативными. Хотите доказательств? Взгляните на следующие примеры:
# Пример 1
$ echo 1 && echo 2 || echo 3
1
2
$
# Пример 2
$ echo 1 || echo 2 && echo 3
1
3
$
Обратите внимание, что крайняя левая команда выполняется всегда, независимо от следующего за ней оператора: порядок вычислений определяется не приоритетом операторов, а их последовательностью.
Так делать не нужно!
Пока мы не ушли далеко от главной темы главы, рассмотрим примеры использования оператора if, которые типичны для сценариев, написанных много лет назад. Мы показываем их, чтобы дополнительно пояснить идиому «большого» if, а также убедить вас никогда не подражать этому стилю. Итак, вот код:
### Не используйте операторы if для таких проверок
if [ $VAR"X" = X ]; then
echo empty
fi
### Или таких
if [ "x$VAR" == x ]; then
echo empty
fi
### И других, подобных им
Здесь всего лишь выполняется проверка, не является ли переменная VAR пустой. Для этого к ее значению добавляется некоторый символ (в этих примерах X и x), и, если в результате получается строка, совпадающая только с этим символом, значит, переменная имеет пустое значение. Не делайте так. Есть лучшие способы выполнить такую проверку. Вот простая альтернатива:
# Значение переменной имеет нулевую длину?
if [[ -z "$VAR" ]]; then
echo empty
fi
Одиночные и двойные квадратные скобки
В примерах кода выше проверяемое условие заключено в одиночные квадратные скобки [ ]. Но главная проблема не в них. В первую очередь, мы рекомендуем избегать приема с добавлением значения и сравнением строк — для таких проверок используйте ключи -z или -n. Почему же в других наших примерах в операторах if и заменяющих их конструкциях используются двойные квадратные скобки [[ и ]]? Они являются дополнением, появившимся в bash и отсутствующим в оригинальной командной оболочке sh. Благодаря этому исключаются некоторые чреватые ошибками ситуации, например когда имя переменной в одних случаях заключено в кавычки, а в других — нет. Мы использовали в двух примерах выше одиночные квадратные скобки, потому что код такого вида часто встречается в старых сценариях. Возможно, вам придется использовать одиночные скобки, если приоритетом является совместимость между различными платформами, в том числе не поддерживающими bash (например, использующими dash). Дополнительно отметим, что двойные квадратные скобки — это ключевые слова, тогда как левая одиночная квадратная скобка — это встроенная функция. Это объясняет некоторые тонкие отличия в их свойствах. Мы советуем по возможности всегда использовать двойные квадратные скобки.
В случае, когда длина значения переменной или строки не равна нулю, можно использовать ключ -n или просто сослаться на переменную:
# Проверяет, что значение переменной имеет ненулевую длину
if [[ -n "$VAR" ]]; then
echo "VAR has a value:" $VAR
fi
# То же самое
if [[ "$VAR" ]]; then
echo even easier this way
fi
Как видите, нет необходимости использовать подход, который был нужен в устаревших версиях команды test («[»). Однако мы посчитали, что вы должны знать о нем, чтобы понимать старые сценарии. Кроме того, теперь вы знаете лучший способ добиться того же результата.
В заключение: стиль и удобочитаемость
В этой главе мы рассмотрели важную идиому bash — проверку условия без оператора if. Такая проверка не похожа на традиционную конструкцию if/then/else, но позволяет получать те же результаты. Если не знать о ней, то некоторые сценарии могут остаться для вас неясными. Эту идио-му целесообразно использовать для проверки всех предварительных условий перед выполнением команды или быстрой проверки ошибок, не нарушая основной логики сценария.
С помощью операторов && и || можно реализовать логику if/then/else. Но в bash есть также и ключевые слова if, then и else, поэтому возникает вопрос: когда использовать их, а когда сокращенные конструкции? Ответ: все зависит от удобочитаемости.
Для определения сложной логики лучше использовать знакомые ключевые слова. А для простых проверок с одиночными командами часто удобнее операторы && и ||, потому что они не отвлекают внимание от основного алгоритма. Используйте help test, чтобы вспомнить, какие проверки выполняют, например, ключи -n и -r, и скопируйте текст справки в памятку на будущее.
В любом случае и в знакомых операторах if, и в идиоматических проверках без if мы рекомендуем использовать синтаксис с двойными квадратными скобками.
Теперь, подробно рассмотрев одну идиому, давайте взглянем на другие, чтобы поднять на новый уровень ваши умения программировать на bash.
Глава 2. Язык циклов
В bash имеются не только циклы for в стиле C, но также другие виды и стили организации циклического выполнения инструкций. Некоторые из них ближе программистам на Python, но у каждого есть свои особые задачи. Существует цикл for без очевидных аргументов, который удобно использовать как в сценариях, так и внутри функций. Также есть похожий на итератор цикл for, значения для которого могут задаваться явно или возвращаться другими командами.
Циклические конструкции
Циклические конструкции распространены в языках программирования. С момента изобретения языка C многие языки
