Почему лишние условия убивают читаемость в Bash

Всем привет. Сегодня хочу поговорить о культуре написания условий bash. Точнее, об использовании отрицаний (НЕ).

 читать первым в телеграм    читать первым в макс

Поводом послужила конструкция, которую я нашел при изучении одного скрипта:

if [[ ! -f "$file" || ! -r "$file" || ! -w "$file" ]];then
  echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
#  exit 1
fi

Расшифруем:

! -f "$file" - НЕ регулярный файл (возможно каталог, устройство, или вообще ничего).
! -r "$file" - у файла НЕт прав на чтение.
! -w "$file" - у файла НЕт прав на запись.

Условия объединены по ИЛИ, значит если выполнится какое-либо - будет ошибка.

С точки зрения логики - все правильно, но у меня лично в глазах рябит от количества палок.

👆 На мой взгляд, отрицания сильно осложняют понимание.

Вспоминаем, что:

! A || ! B эквивалентно ! [ A && B ] ! A && ! B эквивалентно ! [ A || B ]

👆 И помним, что пробелы в условиях bash критически важны.

Таким образом, конструкцию можно переписать, с сохранением функциональности:

if ! [[ -f "$file" && -r "$file" && -w "$file" ]];then
  echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
#  exit 1
fi

Расшифруем:

НЕ (файл регулярный И есть права на чтение И есть на запись). В этой конструкции тоже есть отрицание, но оно уже одно! Конструкцию можно привести к еще более человеческому виду:

if [[ -f "$file" && -r "$file" && -w "$file" ]];then
  :
else
  echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
#  exit 1
fi

Здесь отрицание заменено переносом тела if в тело оператора else.

:” необходимо, потому что между if и else должен быть хотя бы один оператор (в данном случае “:” эквивалент оператора true или nop.

Можно записать и:

if [[ -f "$file" && -r "$file" && -w "$file" ]];then :
else
  echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
#  exit 1
fi

👆 Обратите внимание на “:” после then

Но на мой взгляд, в данном случае, читаемость несколько ухудшится.

Tagd Tagd
Tagd Tagd
Bash Master
Задать вопрос
Хотя первая конструкции и остальные конструкции эквивалентны, но отличие все же есть - скорость работы (Особенно, если в качестве операндов будут использованы функции) И зависит эта скорость будет от сценария работы.

Если при объединении по ИЛИ первый операнд ИСТИНА, то остальные даже проверяться не будут.

При объединении по И все наоборот: остальные проверяться не будут - если первый операнд ЛОЖЬ.

Всем работы без багов.

Комментарии