Jaka jest różnica -a i -e w wyrażeniach warunkowych bash?


12

Od man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Jaka jest więc różnica między [ -a $FILE ]i [ -e $FILE ], jeśli w ogóle?
  2. Jeśli nie ma prawdziwej różnicy, dlaczego istnieją dwie flagi dla tego samego celu?

Tylko programiści znaliby # 2 --- chyba że podzielą się swoją opinią ze społecznością.
Belmin Fernandez

Odpowiedzi:


13

W bash, w kontekście dwóch argumentów testpolecenia, -a filei -e filesą takie same. Ale mają pewną różnicę, ponieważ -ajest również operatorem binarnym.

-eunary jest zdefiniowany przez POSIX, ale -aunary nie jest. POSIX definiuje tylko pliki -abinarne (patrz test POSIX).

POSIX definiuje testzachowanie trzech argumentów :

3 argumenty:

  • Jeśli 2 USD jest wartością binarną podstawową, wykonaj test binarny 1 USD i 3 USD.

  • Jeśli 1 $ to „!”, Zaneguj test na dwa argumenty 2 $ i 3 $.

  • Jeśli 1 $ to „(”, a 3 $ to ”), wykonaj test jednostronny 2 $. W systemach, które nie obsługują opcji XSI, wyniki nie są określone, jeśli 1 $ to „(” a 3 $ to ”)”.

  • W przeciwnym razie uzyskaj nieokreślone wyniki.

Tak -ateż prowadzi do dziwnych wyniku:

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

-ajest uważany za operator binarny w kontekście trzech argumentów. Zobacz Bash FAQ E1 . POSIX wspomina także, że -ajest pobierany z KornShell, ale został później zmieniony na, -eponieważ wprowadza zamieszanie między -abinarnym i jednostkowym -a.

-E-podstawowa, posiadająca podobną funkcjonalność do tej zapewnianej przez powłokę C, została dodana, ponieważ zapewnia ona jedyny sposób, aby skrypt powłoki sprawdził, czy plik istnieje, bez próby jego otwarcia. Ponieważ implementacje mogą dodawać dodatkowe typy plików, przenośny skrypt nie może używać:

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

aby dowiedzieć się, czy foo jest istniejącym plikiem. W historycznych systemach BSD istnienie pliku można ustalić na podstawie:

test -f foo -o -d foo

ale nie było łatwego sposobu ustalenia, czy istniejący plik był zwykłym plikiem. Wczesna propozycja wykorzystywała KornShell -a pierwotny (o tym samym znaczeniu), ale zmieniono go na -e, ponieważ istniały obawy o wysokie prawdopodobieństwo, że ludzie pomylą -a pierwotną z operatorem -a binarnym.

-aplik binarny jest również oznaczony jako przestarzały, ponieważ prowadzi do niejednoznacznego wyrażenia, które ma więcej niż 4 argumenty. Przy tym wyrażeniu> 4 argumenty POSIX definiuje wynik jako nieokreślony.


Fajnie wiedzieć! Teraz jest trochę wyraźniej :)!
polim

9

.1. Jaka jest więc różnica między [-A $ FILE] a [-e $ FILE], jeśli w ogóle?

Nie ma żadnej różnicy.

Zgodnie 505-507w test.cwersji bash 4.2.45(1)-release:

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

Oznacza to, że nie ma rzeczywistej różnicy między obiema flagami.

.2. Jeśli nie ma prawdziwej różnicy, dlaczego istnieją dwie flagi dla tego samego celu?

Zobacz odpowiedź gnouca .


3
Z drugiej strony, biorąc pod uwagę, że -ajest to także operator boolowski (i) w bash, wydaje się, że podatne na błędy jest dodanie tego dodatkowego znaczenia, które jest całkowicie zbędne; Sądzę, że jest to bardziej związane ze zgodnością z innymi implementacjami i / lub kompatybilnością z wcześniejszymi wersjami, które nie miały -e.
celtschk

@celtschk - nie jest podatny na błędy, ale parser powłoki może być. POSIX określa -ai -ologiczne dla [ test ]. Ale niektóre muszle (jak bash) próbowały odróżnić argument od operatora, a [ test ]wyniki były niewiarygodne. Od tego czasu POSIX wymaga, aby każda zgodna powłoka obsługiwała co najmniej 4 argumenty w [ test ]nawiasach.
mikeserv

5

Najlepsza odpowiedź, jaką znalazłem, to ta z pytania StackOverflow:

-ajest przestarzały, dlatego nie jest już wyświetlany na stronie podręcznika /usr/bin/test, ale nadal znajduje się na stronie do bash. Zastosowanie -e. W przypadku pojedynczego „[” wbudowane bash zachowuje się tak samo jak testwbudowane bash, które zachowują się tak samo jak /usr/bin/[i /usr/bin/test (jedno jest dowiązaniem symbolicznym do drugiego). Zauważ, że efekt -azależy od jego pozycji: jeśli jest na początku, to znaczy file exists. Jeśli jest w środku dwóch wyrażeń, oznacza to logiczne and.

[ ! -a /path ] && echo existsnie działa, jak wskazuje instrukcja bash, która -ajest tam uważana za operator binarny, więc powyższe nie jest analizowane jako negate -a ..ale jako if '!' and '/path' is true(niepuste). W związku z tym skrypt zawsze wyświetla dane wyjściowe "-a"(które faktycznie testują pliki) i "! -a"które w rzeczywistości są andtutaj plikami binarnymi .

Na [[, -anie jest używany jako binarny andjuż ( &&jest używany tam), więc jego unikalny celem jest, aby sprawdzić plik istnieje (choć są przestarzałe). Tak więc negacja robi dokładnie to, czego oczekujesz.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.