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/[",... "