В чем разница -a и -e в условных выражениях bash?


12

От man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Так в чем же разница между [ -a $FILE ]и [ -e $FILE ], если таковые имеются?
  2. Если нет реальной разницы, почему существуют два флага для одной и той же цели?

Только разработчики будут знать # 2 --- если они не поделятся своими соображениями с сообществом.
Бельмин Фернандес

Ответы:


13

В bash, с контекстом двух аргументов testкоманды, -a fileи -e fileявляются одинаковыми. Но у них есть некоторая разница, потому что -aэто также бинарный оператор.

-eунарный определяется POSIX, а -aунарный - нет. POSIX определяет только -aдвоичный файл (см. Тест POSIX).

POSIX определяет три аргумента testповедения:

3 аргумента:

  • Если $ 2 - двоичный первичный, выполните двоичный тест $ 1 и $ 3.

  • Если $ 1 равен '!', Отмените тест с двумя аргументами для $ 2 и $ 3.

  • Если $ 1 равен '(', а $ 3 равен ')', выполните унарный тест $ 2. В системах, которые не поддерживают параметр XSI, результаты не указываются, если $ 1 равен '(', а $ 3 равен ')'.

  • В противном случае выдайте неопределенные результаты.

Так -aже приводит к странному результату:

$ [ ! -a . ] && echo true
true

-aрассматривается как бинарный оператор в контексте трех аргументов. Смотрите Bash FAQ вопрос E1 . POSIX также упоминает, что -aон получен из KornShell, но позже был изменен, -eпотому что он делает путаницу между -aдвоичным и -aунарным.

Был добавлен первичный -e, обладающий аналогичными функциональными возможностями, которые предоставляет оболочка C, поскольку он предоставляет единственному способу для сценария оболочки определить, существует ли файл, не пытаясь открыть его. Поскольку реализациям разрешено добавлять дополнительные типы файлов, переносимый скрипт не может использовать:

test -b foo -o -c foo -o -d foo -o -f foo -o -p foo

чтобы узнать, является ли foo существующим файлом. В исторических системах BSD существование файла может быть определено следующим образом:

test -f foo -o -d foo

но не было простого способа определить, что существующий файл является обычным файлом. В раннем предложении использовался основной KornShell -a (с тем же значением), но он был изменен на -e, поскольку существовала обеспокоенность по поводу высокой вероятности того, что люди путают основной -a с двоичным оператором -a.

-aДвоичный файл также помечается как устаревший, поскольку он приводит к некоторому неоднозначному выражению, которое имеет более 4 аргументов. С этим> 4 аргументами выражения, POSIX определяет, что результат не указан.


Круто знать! Теперь это немного понятнее :)!
полим

9

0,1. Так в чем же разница между [-a $ FILE] и [-e $ FILE], если есть?

Там нет никакой разницы вообще.

В строке 505-507в test.cверсии Баша 4.2.45(1)-release:

case 'a':           /* file exists in the file system? */
case 'e':
  return (sh_stat (arg, &stat_buf) == 0);

Это указывает на то, что между обоими флагами нет реальной разницы.

0,2. Если нет реальной разницы, почему существуют два флага для одной и той же цели?

Смотрите ответ gnouc .


3
С другой стороны, учитывая, что -aэто также логический оператор (и) в bash, кажется, что склонен к ошибкам добавить это дополнительное значение, которое является полностью избыточным; Я предполагаю, что это больше связано с совместимостью с какой-либо другой реализацией и / или совместимостью с более ранними версиями, которые не имели -e.
celtschk

@celtschk - это не ошибка, но парсер оболочки может быть. POSIX определяет -aи -oлогические значения для [ test ]. Но некоторые оболочки (вроде bash) не помогли отличить аргумент от оператора, и [ test ]результаты оказались ненадежными. С тех пор POSIX требует, чтобы любая совместимая оболочка обрабатывала как минимум 4 аргумента в [ test ]скобках.
mikeserv

5

Лучший ответ, который я нашел, - это этот вопрос из вопроса StackOverflow:

-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рассматривается бинарный оператор, и поэтому вышеприведенное не анализируется как a, negate -a ..а как if '!' and '/path' is true(непустое). Таким образом, ваш скрипт всегда выводит "-a"(который на самом деле тестирует файлы), и "! -a"который на самом деле здесь является двоичным and.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.