Почему && и || предпочтительнее -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,

Другие вопросы по тегам