Условные конструкции в bash

&& (then branch)

Для наглядности покажу две эквивалентные конструкции:

[[ -n "$DIR" ]] && cd "$DIR"
if [[ -n "$DIR" ]]; then  # help test
	cd "$DIR"
fi

В простых случаях, когда нужно выполнить лишь одну команду при каком-то условии, лучше использовать первую конструкцию - идиому bash; банально, конструкция if с одним действием (внутри ветки then) выглядит громоздко. Тогда как, для определения сложной логики (грубо говоря, больше одной команды “после” условия) лучше использовать конструкцию if.

Польза комментариев (на ютубе??😱😱)

Чтобы избежать недопонимания со стороны людей, незнакомых c bash, лучше дополнять первый (идиоматический) пример комментариями, объясняющими, что делает данный однострочник bash.
Да и вообще комменты в коде помогут читающему быстрее и легче понять этот код.

Link to original

Команда help

Команда help в bash дает краткие подсказки по встроенным функциям bash вместо объемного текста в man.

help test  # подсказки о выражениях проверки условий (-n и т.д.)
help [  # synonym for the "test" builtin ([...])
Link to original


|| (else branch)

Две эквивалентные конструкции:

[[ -z "$DIR" ]] || cd "$DIR"
if [[ -z "$DIR" ]]; then
	:
else
	cd "$DIR"
fi

Двоеточие (:) - пустая конструкция, которая ничего не делает.

Offtop

К слову, вот два способа проверки, например, переменной на ненулевую длину:

[[ -n "$VAR" ]] &&  echo "VAR is not empty"
# и вариант попроще:
[[ "$VAR" ]] &&  echo "VAR is not empty"

Квадратные скобки и операторы сравнения

Сравни три выражения:

if cd "$DIR"; then :; fi
if [ cd "$DIR" ]; then :; fi
if [[ cd "$DIR" ]]; then :; fi

Без квадратных скобок

Без квадратных скобок оболочка выполнит команду, которая и вернет код возврата, который if будет интерпретировать как true/false и выбирать then/else ветки. Bash еще и позволяет помещать в if конвейеры (например, cmd | sort | wc), откуда вернется статус выполнения последней команды и т.д. (такой подход чреват ошибками set -o pipefail в тему).

Одинарные квадратные скобки

Вариант с [ ] (одинарными квадратными скобками) запускает встроенную команду test. Открывающая квадратная скобка [ - это встроенная команда оболочки, аналог команды test, но отличающаяся обязательным конечным аргументом ] .

Двойные квадратные скобки

Двойные квадратные скобки являются ключевым словом, определяющим составную команду. Похожи во многом на одинарные, но с одним из отличиев: [[ ]] поддерживает доп. оператор сравнения =~, позволяющий юзать RegEx:

if [[ "$filename" =~ *abc*.*jpg ]]; then :; fi

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

Еще одно отличие больше стилистическое (но влияет на переносимость):

if [[ "$VAR" == "literal" ]]; then :; fi
if [ "$VAR" = "literal" ]; then :; fi

Одиночный знак равенства предпочтительнее с [ ] (стандарт POSIX).

Следующее отличие: внутри [[ ]] операторы > и < выполняют “лексикографическое сравнение с использованием текущих региональных настроек”, тогда как test и [ выполняют простое сравнение на основе ASCII. В [ ] еще нужно будет экранировать символы < и > ([$x \> $y]), иначе они будут интерпретироваться как операторы перенаправления. Потому что [ , как и test, является встроенной командой, а не ключевым словом (а [[ ]] являются ключевым словом, поэтому таких траблов нет).

Поэтому [[ ]] предпочтительнее.

Старый синтаксис числовых сравнений

Синтаксис с квадратными скобками позволяет использовать старый синтаксис числовых сравнений (напоминающий FORTRAN). Это всякие -le (меньше или равно - less-than-or-equal) и т.д.
И здесь больше подходят [[ ]]. Ибо аргументы по обе стороны от этого старого оператора в [ ] должны быть целочисленными, а в [[ ]] аргументы могут быть даже целыми арифметическими выражениями (но их лучше выполнять в (( )) ):

[[ "1 + 2" -le "9203 * 2" ]] && echo da

Для сравнения арифметических выражений лучше применять (( )), которые позволяют использовать привычные операторы сравнения (+свобода в применении пробелов):

(( 1 + 2 <= 9203 * 2 )) && echo da

В круглых скобках не нужен оператор $ для получения значения переменной (за исключением позиционных аргументов $1, $2 и т.д.):

if (( VAL < 12 )); then
	:
fi

Случай, где 0 = ложь

В двойных скобках воспроизводится числовая (C/Java/Python) логика повышенного уровня. Любое ненулевое значение считается истинным, и только 0 - ложным. Например:

(( $? )) && echo "previous command failed"

если предыдущая команда завершилась неудачно, то $? будет содержать ненулевое значение; внутри (( )) ненулевое значение будет истинным и ветвь then будет выполнена.


Соусы:
Книга “Идиомы Bash Глава 2. “Идиома большого if
Книга “Идиомы Bash Глава 5. “Выражения и арифметикаСоставные команды (первая половина)” (для Квадратные скобки и операторы сравнения)
Книга “Bash и кибербезопасность Глава 2. “Основы работы с bash

bash