Bash, если опция -a vs -e

Оба параметра "-a" и "-e" в документации Bash (http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions):

-a file
    True if file exists.
-e file
    True if file exists. 

Попытавшись понять, в чем разница, я запустил следующий script:

resin_dir=/Test/Resin_wheleph/Results

if [ -e ${resin_dir} ] ; then
    echo "-e ";
fi

if [ ! -e ${resin_dir} ] ; then
    echo "! -e";
fi

if [ -a ${resin_dir} ] ; then
    echo "-a";
fi

if [ ! -a ${resin_dir} ] ; then
    echo "! -a";
fi

/Test/Resin_wheleph/Результаты существуют и являются каталогом. И это то, что я получаю:

-e
-a
! -a

который кажется немного странным (обратите внимание на "-a" и "! -a" ). Но когда я использую двойные скобки (например, if [[ -e ${resin_dir} ]]) в аналогичном script, он дает разумный вывод:

-e
-a

Итак:

  • В чем разница между параметрами "-a" и "-e"?
  • Почему "-a" производит странный результат при использовании внутри отдельных скобок?

Ответ 1

Я исследовал, и это довольно волосатое:

-a устарел, поэтому больше не указан в man-странице для /usr/bin/test, но все еще в одном для bash. Используйте -e. Для одиночного '[', встроенный bash ведет себя так же, как встроенный test bash, который ведет себя так же, как /usr/bin/[ и /usr/bin/test (один является символической ссылкой на другой). Обратите внимание, что эффект -a зависит от его положения: если он в начале, это означает file exists. Если он находится в середине двух выражений, это означает логический and.

[ ! -a /path ] && echo exists не работает, так как руководство bash указывает, что -a считается там двоичным оператором, и поэтому выше не анализируется как negate -a .., а как a if '!' and '/path' is true ( не пусто). Таким образом, ваш script всегда выводит "-a" (который фактически проверяет файлы) и "! -a", который на самом деле является двоичным and здесь.

Для [[, -a больше не используется как двоичный and (там используется &&), поэтому его уникальная цель - проверить наличие там файла (хотя и устаревшего). Таким образом, отрицание фактически делает то, что вы ожидаете.

Ответ 2

Опция '-a' для тестового оператора имеет одно значение как унарный оператор, а другое как двоичный оператор. В качестве двоичного оператора это "и" connective (и "-o" - это "или" соединительный элемент). Как унарный оператор, он, по-видимому, проверяет существование файла.

Система autoconf рекомендует избегать использования '-a', потому что это вызывает путаницу; теперь я понимаю, почему. Действительно, в переносном программировании оболочки лучше всего комбинировать условия с "&&" или "||".

Я думаю, что @litb на правильном пути. Когда у вас есть < ! -a ${resin_dir} ', Bash может интерпретировать его как "строка"! непустой и является строкой в ​​'$ {resin_dir}', не пустой, для которой ответ да. Оболочка Korn имеет другое представление, а оболочка Bourne - еще один вид - поэтому держитесь подальше от '-a.

В Solaris 10:

$ bash -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
Bad
$ ksh -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
OK
$ sh -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
sh: test: argument expected
$

Ответ 3

Двойная скобка [[exp]] является встроенной bash. В bash -a и -e одинаковы, возможно, для некоторой обратной совместимости.

Единая скобка [exp] является псевдонимом для внешней команды "test". В "тесте", -а является логическим И. Хотя [ничего И $STRING] выглядит так, как будто оно должно быть ложным, тест имеет некоторые синтаксические причуды, поэтому я рекомендую использовать bash builtin [[exp]], который имеет тенденцию быть более разумным.

Примечание: bash действительно вызывает call/bin/[при использовании "[".

$ [ $UNASIGNED_VAR == "bar" ]
bash: [: ==: unary operator expected

ошибка показывает bash, называемую [. В strace также отображается "execve" ( "/usr/bin/[",... "