Яка різниця -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це також двійковий оператор.

-eunary визначається POSIX, але -aunry - ні. 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 E1 . POSIX також згадує, що -aотримується від KornShell, але згодом було змінено, -eоскільки він робить заплутаним між -aбінарним та -aунарним.

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

тест -b foo -o -c foo -o -d foo -o -f foo -o -p foo

щоб з'ясувати, чи foo - це вже існуючий файл. У історичних системах BSD існування файлу можна визначити:

тест -f foo -o -d foo

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

-aдвійковий також позначений як застарілий, тому що це призводить до деякого неоднозначного вираження, яке має більше 4 аргументів. За допомогою цих> 4 аргументів вираз, POSIX визначає результат не визначений.


Класно знати! Тепер трохи зрозуміліше :)!
полім

9

.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);

Це вказує на відсутність реальної різниці між обома прапорами.

.2. Якщо немає реальної різниці, чому існують два прапори з однаковою метою?

Дивіться відповідь gnouc .


3
З іншого боку, враховуючи, що -aце також булевий оператор (і) в баші, здається, помилка схильна додати це додаткове значення, яке є абсолютно зайвим; Я б здогадувався, що це більше пов'язано із сумісністю з якоюсь іншою реалізацією та / або сумісністю з попередніми версіями, яких не було -e.
celtschk

@celtschk - це не багпрон, але аналізатор оболонки може бути. POSIX вказує -aі -oбулі для [ test ]. Але деякі снаряди (як bash) засмоктувались при відмежуванні аргументу від оператора, і [ test ]результати були недостовірними. З того часу POSIX вимагає, щоб будь-яка сумісна оболонка обробляла щонайменше 4 аргументи в [ test ]дужках.
mikeserv

5

Найкраща відповідь, яку я знайшов, - це ця, з питання StackOverflow:

-aзастаріла, тому більше не перераховується на сторінці сторінки /usr/bin/test, але все ж у тій, що є для bash. Використовуйте -e. Для одиночного '[', bash вбудований поводиться так само, як і testbash вбудований, який поводиться так само, як /usr/bin/[і /usr/bin/test (один є символьним посиланням на інший). Зверніть увагу, ефект -aзалежить від його положення: якщо він знаходиться на старті, це означає file exists. Якщо воно посередині двох виразів, це означає логічно and.

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.