Qual è la differenza di -a e -e nelle espressioni condizionali di bash?


12

Da man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Quindi qual è la differenza tra [ -a $FILE ]e [ -e $FILE ], se presente?
  2. Se non c'è alcuna differenza reale, perché esistono due flag per lo stesso scopo?

Solo gli sviluppatori saprebbero # 2 --- a meno che non condividano il loro ragionamento con la comunità.
Belmin Fernandez,

Risposte:


13

In bash, con il contesto del testcomando due argomenti , -a filee -e filesono uguali. Ma hanno qualche differenza, perché -aè anche un operatore binario.

-eunario è definito da POSIX, ma -aunario no. POSIX definisce solo -abinario (vedi test POSIX).

POSIX definisce il testcomportamento di tre argomenti :

3 argomenti:

  • Se $ 2 è un primario binario, eseguire il test binario di $ 1 e $ 3.

  • Se $ 1 è '!', Annulla il test a due argomenti di $ 2 e $ 3.

  • Se $ 1 è '(' e $ 3 è ')', esegui il test unario di $ 2. Sui sistemi che non supportano l'opzione XSI, i risultati non sono specificati se $ 1 è '(' e $ 3 è ')'.

  • Altrimenti, produce risultati non specificati.

Quindi -aporta anche a strani risultati:

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

-aè considerato operatore binario nel contesto di tre argomenti. Vedi la domanda frequente Bash E1 . POSIX menziona anche che -aè stato ottenuto da KornShell ma è stato modificato in seguito -eperché crea confusione tra -abinario e -aunario.

Il primario -e, che possiede funzionalità simili a quelle fornite dalla shell C, è stato aggiunto perché fornisce l'unico modo per uno script di shell di scoprire se esiste un file senza provare ad aprire il file. Poiché alle implementazioni è consentito aggiungere altri tipi di file, uno script portatile non può utilizzare:

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

per scoprire se foo è un file esistente. Sui sistemi BSD storici, l'esistenza di un file potrebbe essere determinata da:

test -f foo -o -d foo

ma non c'era modo semplice per determinare che un file esistente era un file normale. Una prima proposta utilizzava il KornShell -a primario (con lo stesso significato), ma questo è stato cambiato in -e perché c'erano preoccupazioni sull'alta probabilità che gli umani confondessero il -a primario con l'operatore binario -a.

-abinario è anche contrassegnato come obsoleto, perché porta a qualche espressione ambigua, che ha più di 4 argomenti. Con l'espressione di questi> 4 argomenti, POSIX definisce il risultato non specificato.


Bello da sapere! Ora è un po 'più chiaro :)!
polimero

9

.1. Quindi qual è la differenza tra [-a $ FILE] e [-e $ FILE], se presente?

Non c'è alcuna differenza.

In linea 505-507con test.cla versione bash 4.2.45(1)-release:

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

Ciò indica che non esiste alcuna differenza reale tra le due bandiere.

.2. Se non c'è alcuna differenza reale, perché esistono due flag per lo stesso scopo?

Vedi la risposta di Gnouc .


3
D'altra parte, dato che -aè anche un operatore booleano (e) in bash, sembra incline ad aggiungere questo significato aggiuntivo che è completamente ridondante; Immagino che sia più legato alla compatibilità con qualche altra implementazione e / o compatibilità con le versioni precedenti che non avevano -e.
Celtschk,

@celtschk - non è bugprone, ma potrebbe essere il parser della shell. POSIX specifica -ae -obooleani per [ test ]. Ma alcune conchiglie (come bash) hanno fatto schifo nel distinguere un argomento da un operatore e i [ test ]risultati non erano affidabili. Da allora POSIX ha richiesto che qualsiasi shell conforme gestisse almeno 4 argomenti tra [ test ]parentesi.
Mikeserv,

5

La migliore risposta che ho trovato è questa, da una domanda StackOverflow:

-aè deprecato, quindi non è più elencato nella manpage /usr/bin/test, ma ancora in quello per bash. Usa -e. Per singolo '[', l'integrato bash si comporta come l' testintegrato bash, che si comporta come /usr/bin/[e /usr/bin/test (l'uno è un collegamento simbolico all'altro). Nota l'effetto di -adipende dalla sua posizione: se è all'inizio, significa file exists. Se è nel mezzo di due espressioni, significa logico and.

[ ! -a /path ] && echo existsnon funziona, come indica il manuale di bash che -aè considerato un operatore binario lì, e quindi quanto sopra non viene analizzato come negate -a ..ma come if '!' and '/path' is true(non vuoto). Pertanto, il tuo script genera sempre "-a"(che in realtà verifica i file) e "! -a"che in realtà è un file binario andqui.

Perché [[, -anon viene più utilizzato come binario and( &&viene utilizzato lì), quindi il suo scopo unico è quello di verificare la presenza di un file lì (sebbene sia deprecato). Quindi, la negazione in realtà fa quello che ti aspetti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.