Perché [-n] non è falso come [-n “”]?


20

La mia domanda è sui valori di ritorno prodotti da questo codice:

if [ -n ]; then echo "true"; else echo "false"; fi

Questo stampa true.

Il suo test complementare che utilizza [ -z ]anche stampa true:

if [ -z ]; then echo "true"; else  echo "false"; fi

Nel codice sopra, perché il [ -n ]test assume il valore di stringa che non viene passato affatto, come non nullo?

Viene stampato il codice seguente false. Ciò è previsto poiché il valore della stringa passata è nullo e di lunghezza zero.

if [ -n "" ]; then echo "true"; else  echo "false"; fi

Risposte:


14

[x] è equivalente a [ -nx] anche se x inizia con -purché non sia presente alcun operando.

$ [ -o ] ; echo $?
0
$ [ -eq ] ; echo $?
0
$ [ -n -o ] ; echo $?
0
$ [ -n -eq ] ; echo $?
0

4
Nota che storicamente [ -t ]stava testando se stdout era un terminale (abbreviazione di [ -t 1 ]) e alcune shell lo stanno ancora facendo (nel caso di ksh93solo quando -tè letterale), quindi è meglio usare [ -n "$var" ]di [ "$var" ]. Anche se ciò fallirebbe ancora in alcune vecchie testimplementazioni per valori di $varlike =, nel qual caso [ "" != "$var" ]o [ "x$var" != x ]o case $x in "")...potrebbe essere migliore.
Stéphane Chazelas,

3
Scelta interessante di -oqui. In alcune shell come bash, -oè sia un operatore unario (test se è impostata un'opzione) sia binario (o), quindi cose come [ ! -o monitor ]sono ambigue. Sta testando che l' monitoropzione non è impostata o che una !o entrambe monitorsono stringhe non vuote? Le regole POSIX decidono: quest'ultima (che è diverso con [[ ! -o monitor ]]).
Stéphane Chazelas,

30

[ -n ]non utilizza il -ntest.

L' -nin [ -n ]non è un test a tutti. Quando c'è solo un argomento tra [e ], quell'argomento è una stringa che viene testata per vedere se è vuota. Anche quando quella stringa ha un carattere iniziale -, viene comunque interpretata come un operando, non un test. Poiché la stringa -nnon è vuota - contiene due caratteri -e n, non zero caratteri - viene [ -n ]valutata come vera.

Come dice Ignacio Vazquez-Abrams , dove stringè un singolo argomento, la prova eseguita stringin è la stessa della prova effettuata su di essa . Quando succede , non succede nulla di speciale. L' in e la seconda in sono semplicemente stringhe in fase di test per il vuoto.[ string ][ -n string ]string-n-n[ -n ]-n[ -n -n ]

Quando c'è solo un argomento tra [e ], quell'argomento è sempre una stringa da testare per non vuoto, anche se capita di essere chiamato lo stesso di un test. Allo stesso modo, quando ci sono due argomenti tra [e ]e il primo è -n, il secondo è sempre una stringa da testare per non vuoto, anche se capita di essere chiamato lo stesso di un test. Questo semplicemente perché la sintassi per [insiste sul fatto che un singolo argomento tra [e ]o dopo -nsia un operando di stringa.

Per lo stesso motivo che [ -n ]non utilizza il -ntest, [ -z ]non utilizza il -ztest.


È possibile saperne di più su [nel bashesaminando l'aiuto per questo. Si noti che è incorporato una shell :

$ type [
[ is a shell builtin

Quindi puoi correre help [per ottenere aiuto su di esso:

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

Per ulteriori informazioni, incluso quali test sono supportati e come funzionano, dovrai consultare la guida test. Quando esegui il comando help test, otterrai un elenco dettagliato. Invece di riprodurre tutto, ecco la parte sugli operatori di stringa:

      -z STRING      True if string is empty.

      -n STRING
         STRING      True if string is not empty.

      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.

Notalo -n STRINGe STRINGfai solo la stessa cosa: verificano se la stringa STRINGnon è vuota.


2
Buona spiegazione
Sergiy Kolodyazhnyy,

1
Forse anche menzionare che ciò ha implicazioni per le variabili non quotate che non sono impostate, in questo modo: paste.ubuntu.com/25831047
Sergiy Kolodyazhnyy,

1
@SergiyKolodyazhnyy Penso che potrebbe essere migliore in una risposta separata. Le variabili non impostate, o impostate ma vuote, o che contengono solo IFSspazi bianchi, lo faranno; le variabili che contengono più parole anziché zero producono un altro effetto e possono causare l'esecuzione di un test completamente diverso. Le stringhe che appaiono letteralmente con l'intento di essere operandi funzioneranno correttamente solo se non contengono spazi o tabulazioni o se sono quotate. La risposta sarebbe molto più lunga e complicata se avessi trattato questo argomento in modo accessibile. Se decidi di pubblicare una risposta, non esitare a @ me qui a riguardo!
Eliah Kagan,

@Eliah Kagan, la tua risposta è più completa e dettagliata sebbene la risposta di Ignacio Vazquez-Abrams abbia risposto alla mia domanda.
Ravi Kumar,

1
Penso che ti manchi la ragione che è e deve essere così: in caso contrario, non [ "$var" ]sarebbe mai utilizzabile come test perché $varpotrebbe espandersi -n.
R ..

12

[ -n ]è vero perché il [comando (alias il testcomando) agisce sul numero di argomenti che gli viene dato. Se viene fornito solo un singolo argomento, il risultato è "vero" se l'argomento è una stringa non vuota. "-n" è una stringa con 2 caratteri, non vuota, quindi "vera".

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.