Warum ist [-n] nicht falsch wie [-n “”]?

20

Meine Frage bezieht sich auf Rückgabewerte, die mit diesem Code erstellt wurden:

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

Dies wird gedruckt true.

Sein ergänzender Test, der [ -z ]auch Drucke verwendet true:

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

Warum geht der [ -n ]Test im obigen Code davon aus, dass der Zeichenfolgenwert, der überhaupt nicht übergeben wird, nicht null ist?

Der folgende Code wird gedruckt false. Dies wird erwartet, da der übergebene Zeichenfolgenwert null ist und die Länge null hat.

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

Antworten:

14

[x] ist äquivalent zu [ -nx,] auch wenn x mit beginnt, -vorausgesetzt, es gibt keinen Operanden.

$ [ -o ] ; echo $?
0
$ [ -eq ] ; echo $?
0
$ [ -n -o ] ; echo $?
0
$ [ -n -eq ] ; echo $?
0
Ignacio Vazquez-Abrams
quelle
4
Beachten Sie, dass in der [ -t ]Vergangenheit getestet wurde, ob stdout ein Terminal war (Abkürzung für [ -t 1 ]), und dass einige Shells dies immer noch tun ( ksh93nur wenn dies -twörtlich ist). Daher ist es besser, es zu verwenden [ -n "$var" ]als [ "$var" ]. Obwohl das wäre immer noch in einigen alten scheitern testImplementierungen für Werte $varwie =, in welchem Fall [ "" != "$var" ]oder [ "x$var" != x ]oder case $x in "")...besser sein kann.
Stéphane Chazelas
3
Interessante Wahl von -ohier. In einigen Shells wie bash, -oist sowohl ein einstelliger (Test , wenn eine Option ist gesetzt) und binäre (oder) Operator, so Dinge wie [ ! -o monitor ]mehrdeutig ist. Ist es zu testen , dass die monitorOption nicht gesetzt ist, oder dass entweder !oder monitorsind nicht leere Strings? POSIX-Regeln entscheiden: Letzteres (das ist anders bei [[ ! -o monitor ]]).
Stéphane Chazelas
30

[ -n ]benutzt den -nTest nicht.

Das -nIn [ -n ]ist überhaupt kein Test. Wenn zwischen [und nur ein Argument ]steht, handelt es sich um eine Zeichenfolge, die daraufhin überprüft wird, ob sie leer ist. Auch wenn diese Zeichenfolge eine führende Position hat -, wird sie immer noch als Operand und nicht als Test interpretiert. Da die Zeichenfolge -nnicht leer ist - es enthält zwei Zeichen, -und n, nicht Null characters-- [ -n ]auswertet auf true.

Wie Ignacio Vazquez-Abrams sagt , stringist der Test, der stringin ausgeführt wird, derselbe wie der Test, der von ausgeführt wird . Wann passiert, passiert nichts Besonderes. Das In und das Second In sind einfach Saiten, die auf Leere geprüft werden.[ string ][ -n string ]string-n-n[ -n ]-n[ -n -n ]

Wenn zwischen [und nur ein Argument steht ], handelt es sich bei diesem Argument immer um eine Zeichenfolge, die auf Unversehrtheit geprüft werden soll, auch wenn sie zufällig den gleichen Namen hat wie ein Test. Wenn zwischen [und zwei Argumente stehen ]und das erste Argument ein Argument ist -n, ist das zweite immer eine Zeichenfolge, die auf Unversehrtheit geprüft werden soll, auch wenn es zufällig den gleichen Namen hat wie ein Test. Dies liegt einfach daran, dass die Syntax für [darauf besteht, dass ein einzelnes Argument zwischen [und ]oder nach -neinem Zeichenfolgenoperanden ist.

Aus dem gleichen Grund, [ -n ]der den -nTest [ -z ]nicht verwendet, wird der -zTest nicht verwendet .


Sie können mehr darüber erfahren , [in bashfür sie durch die Untersuchung der Hilfe. Beachten Sie, dass eine Shell eingebaut ist :

$ type [
[ is a shell builtin

So können Sie laufen help [, um Hilfe zu bekommen:

$ 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 `['.

Weitere Informationen, einschließlich der unterstützten Tests und ihrer Funktionsweise, finden Sie in der Hilfe test. Wenn Sie den Befehl ausführen help test, wird eine detaillierte Liste angezeigt. Anstatt alles zu reproduzieren, ist hier der Teil über String-Operatoren:

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

Beachten Sie dies -n STRINGund STRINGmachen Sie dasselbe: Sie testen, ob die Zeichenfolge STRINGnicht leer ist.

Eliah Kagan
quelle
2
Gute Erklärung
Sergiy Kolodyazhnyy
1
Erwähnen Sie möglicherweise auch, dass dies Auswirkungen auf nicht in Anführungszeichen gesetzte Variablen hat, wie z. B. paste.ubuntu.com/25831047
Sergiy Kolodyazhnyy 27.10.17
1
@SergiyKolodyazhnyy Ich denke, es kann in einer separaten Antwort besser sein. Variablen, die nicht gesetzt oder gesetzt, aber leer sind oder nur IFSLeerzeichen enthalten , tun dies. Variablen, die mehrere Wörter anstelle von Null enthalten, erzeugen einen anderen Effekt und können dazu führen, dass ein völlig anderer Test ausgeführt wird. Zeichenfolgen, die buchstäblich in der Absicht angezeigt werden, Operanden zu sein, funktionieren nur dann ordnungsgemäß, wenn sie keine Leerzeichen oder Tabulatoren enthalten oder in Anführungszeichen gesetzt sind. Die Antwort würde viel länger und komplizierter werden, wenn ich dieses Thema auf zugängliche Weise behandeln würde. Wenn Sie sich dazu entschließen, eine Antwort zu schreiben, wenden Sie sich bitte hier an @ me!
Eliah Kagan
@Eliah Kagan, Ihre Antwort ist vollständiger und detaillierter, obwohl die Antwort von Ignacio Vazquez-Abrams meine Frage beantwortet hat.
Ravi Kumar
1
Ich denke, Sie vermissen den Grund, warum es so ist und sein muss: Wenn nicht, [ "$var" ]wäre es niemals als Test verwendbar, weil $vares sich erweitern könnte -n.
R ..
12

[ -n ]ist wahr, weil der [Befehl (alias der testBefehl) auf die Anzahl der Argumente wirkt, die ihm gegeben wurden. Wenn nur ein einziges Argument angegeben wird, ist das Ergebnis "true", wenn das Argument eine nicht leere Zeichenfolge ist. "-n" ist ein String mit 2 Zeichen, nicht leer, daher "true".

Glenn Jackman
quelle