Was ist der Unterschied zwischen -a und -e in den bedingten Ausdrücken von bash?

12

Von man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Was ist also der Unterschied zwischen [ -a $FILE ]und [ -e $FILE ], falls vorhanden?
  2. Wenn es keinen wirklichen Unterschied gibt, warum existieren zwei Flags für denselben Zweck?
polym
quelle
Nur die Entwickler würden # 2 kennen - es sei denn, sie teilten der Community ihre Argumentation mit.
Belmin Fernandez

Antworten:

13

In bash, mit Kontext von zwei Argumenten testBefehl, -a fileund -e filesind gleich. Sie haben aber einen gewissen Unterschied, da -aes sich auch um einen binären Operator handelt.

-eunary wird von POSIX definiert, -aunary jedoch nicht. POSIX definiert nur -aBinär (siehe Test POSIX).

POSIX definiert das testVerhalten von drei Argumenten :

3 Argumente:

  • Wenn $ 2 eine binäre Primärdatenbank ist, führen Sie den Binärtest von $ 1 und $ 3 durch.

  • Wenn $ 1 '!' Ist, negieren Sie den Test mit zwei Argumenten von $ 2 und $ 3.

  • Wenn $ 1 '(' und $ 3 ')' ist, führen Sie den unären Test von $ 2 durch. Auf Systemen, die die XSI-Option nicht unterstützen, werden die Ergebnisse nicht angegeben, wenn $ 1 '(' und $ 3 ')' ist.

  • Andernfalls führen Sie zu nicht spezifizierten Ergebnissen.

Das -aführt also auch zu einem seltsamen Ergebnis:

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

-awird im Kontext von drei Argumenten als binärer Operator betrachtet. Siehe Bash FAQ Frage E1 . POSIX erwähnt auch, dass -aes von KornShell stammt, aber später geändert wurde, -eweil es die Verwechslung zwischen -abinär und -aunär macht.

Das -e-Primärsystem mit ähnlichen Funktionen wie die C-Shell wurde hinzugefügt, da es die einzige Möglichkeit für ein Shell-Skript darstellt, herauszufinden, ob eine Datei vorhanden ist, ohne zu versuchen, die Datei zu öffnen. Da Implementierungen zusätzliche Dateitypen hinzufügen dürfen, kann ein portables Skript Folgendes nicht verwenden:

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

um herauszufinden, ob foo eine vorhandene Datei ist. Auf historischen BSD-Systemen kann das Vorhandensein einer Datei bestimmt werden durch:

test -f foo -o -d foo

Es gab jedoch keine einfache Möglichkeit, festzustellen, ob eine vorhandene Datei eine reguläre Datei war. In einem frühen Vorschlag wurde die KornShell -a-Primärdatenbank (mit derselben Bedeutung) verwendet. Diese wurde jedoch in -e geändert, da Bedenken hinsichtlich der hohen Wahrscheinlichkeit bestehen, dass Menschen die Primärdatenbank -a mit dem Binäroperator -a verwechseln.

-abinär wird auch als veraltet markiert, da es zu einem mehrdeutigen Ausdruck führt, der mehr als 4 Argumente enthält. Mit diesem Ausdruck> 4 Argumente definiert POSIX, dass das Ergebnis nicht angegeben ist.

cuonglm
quelle
Cool zu wissen! Jetzt ist es etwas klarer :)!
Polym
9

.1. Was ist also der Unterschied zwischen [-a $ FILE] und [-e $ FILE], falls vorhanden?

Es gibt überhaupt keinen Unterschied.

In Zeile 505-507in test.cder Bash - Version 4.2.45(1)-release:

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

Dies zeigt an, dass zwischen beiden Flags kein wirklicher Unterschied besteht.

.2. Wenn es keinen wirklichen Unterschied gibt, warum existieren zwei Flags für denselben Zweck?

Siehe Gnoucs Antwort.

polym
quelle
3
Auf der anderen Seite scheint es angesichts der Tatsache, dass -aes sich auch um einen booleschen Operator (und) in bash handelt, fehleranfällig zu sein, diese zusätzliche Bedeutung hinzuzufügen, die vollständig redundant ist. Ich würde vermuten, dass dies eher mit der Kompatibilität mit einer anderen Implementierung und / oder der Kompatibilität mit früheren Versionen zusammenhängt, die dies nicht hatten -e.
Celtschk
@celtschk - es ist nicht fehleranfällig, aber der Parser der Shell kann sein. POSIX gibt die -aund -o-Booleschen Werte für an [ test ]. Aber einige Muscheln (wie bash) saugten daran, ein Argument von einem Operator zu unterscheiden, und die [ test ]Ergebnisse waren unzuverlässig. Seitdem verlangt POSIX, dass jede kompatible Shell mindestens 4 Argumente in den [ test ]Klammern verarbeitet.
Mikeserv
5

Die beste Antwort, die ich gefunden habe, ist diese aus einer StackOverflow-Frage:

-aist veraltet, wird also nicht mehr in der Manpage aufgeführt /usr/bin/test, aber immer noch in der für Bash. Verwenden Sie -e. Für ein einzelnes '[' verhält sich das eingebaute Bash genauso wie das testeingebaute Bash, das sich genauso verhält wie /usr/bin/[und /usr/bin/test (das eine ist ein Symlink zum anderen). Beachten Sie, dass die Wirkung von -avon seiner Position abhängt: Wenn es am Anfang ist, bedeutet es file exists. Wenn es sich um zwei Ausdrücke handelt, bedeutet dies logisch and.

[ ! -a /path ] && echo existsfunktioniert nicht, wie das Bash-Handbuch hervorhebt, das -adort als binärer Operator betrachtet wird, und daher wird das Obige nicht als, negate -a ..sondern als if '!' and '/path' is true(nicht leer) analysiert . Daher gibt Ihr Skript immer aus "-a"(was tatsächlich auf Dateien testet) und "! -a"was hier tatsächlich eine Binärdatei andist.

Für [[, -anicht als binäres verwendet wird andmehr ( &&wird es), so sein einzigartiger Zweck für eine Datei zu überprüfen , ist es (wenn auch veraltet ist). Negation macht also tatsächlich das, was Sie erwarten.

jimm-cl
quelle