Почему && и || предпочтительнее -a и -o
При написании if
блоки в bash, shellcheck говорит мне, что &&
а также ||
предпочтительнее использования -a
а также -o
,
Зачем? Это быстрее или просто стилистическое предпочтение, чтобы скрипты выглядели чище?
Конкретное сообщение, которое я получаю:
^-- SC2166: Prefer [ p ] || [ q ] as [ p -o q ] is not well defined.
1 ответ
Из спецификации POSIX дляtest
:
4 аргумента:
Результаты не уточняются.
[OB XSI] [Option Start] В системах, соответствующих XSI, комбинации основных цветов и операторов должны оцениваться с использованием правил приоритета и ассоциативности, описанных ранее. Кроме того, двоичные первичные числа сравнения строк '=' и "!=" Должны иметь более высокий приоритет, чем любой унарный первичный. [Вариант Конец]
Таким образом: Использование test
с более чем тремя аргументами - и если вы используете -a
или же -o
, вы зависите от этого - не ведите себя так, как явно указано в расширенном POSIX.
Теперь, почему это так? Потому что есть сценарии, в которых парсер может делать неправильные вещи в зависимости от значений переменных.
Вы помните, как люди давали советы, чтобы делать такие вещи?
if [ "x$foo" = "x$bar" ]; then ...
... это глупо и древне, верно? На самом деле нет! Рассмотрим случай, когда foo=(
а также bar=)
и кто-то запускает такую команду:
if [ "$foo" -a "$bar" ]
Это распространяется на следующее:
if [ ( -a ) ]
... и как мы можем разобрать это? Ну, это может быть оператор группировки (да, test
исторически было указано, чтобы поддержать их), проверяя, -a
ненулевой; или это может быть проверка того, (
а также )
сами непустые строки; это неоднозначно. Эта двусмысленность почему -a
а также -o
больше не являются предпочтительным синтаксисом.
Итак, как выглядит замена? Вместо:
[ "$foo" -gt "$bar" -a "$foo" -lt "$qux" ]
... вы бы написали это:
[ "$foo" -gt "$bar" ] && [ "$foo" -lt "$qux" ]
... закрытие двух тестовых выражений и использование синтаксиса оболочки для объединения их вывода. поскольку [
/ test
это встроенная оболочка, ее не нужно выполнять как внешнюю команду, поэтому она не имеет такой производительности, которая была бы в 70-х годах при запуске test
означало призывать /usr/bin/test
,