Ich sehe dies oft in den Build-Skripten von Projekten, die Autotools verwenden (Autoconf, Automake). Wenn jemand den Wert einer Shell-Variablen überprüfen möchte, verwendet er häufig diese Redewendung:
if test "x$SHELL_VAR" = "xyes"; then
...
Was ist der Vorteil gegenüber der einfachen Überprüfung des Werts wie folgt:
if test $SHELL_VAR = "yes"; then
...
Ich denke, es muss einen Grund geben, warum ich das so oft sehe, aber ich kann nicht herausfinden, was es ist.
"x$Variable"
. Diese Frage ist ein Duplikat dieser Frage.X""
. Auch diese Frage ist praktisch ein Duplikat dieser Frage oder deckt den größten Teil des gleichen Grundes ab. Beide Duplikate haben einige gute Antworten.Antworten:
Wenn Sie eine Shell verwenden, die eine einfache Ersetzung durchführt und die
SHELL_VAR
Variable nicht vorhanden ist (oder leer ist), müssen Sie auf die Randfälle achten. Die folgenden Übersetzungen werden passieren:if test $SHELL_VAR = yes; then --> if test = yes; then if test x$SHELL_VAR = xyes; then --> if test x = xyes; then
Die erste davon erzeugt einen Fehler, da das erste Argument zu
test
verschwunden ist. Der zweite hat dieses Problem nicht.Ihr Fall lautet wie folgt:
if test "x$SHELL_VAR" = "xyes"; then --> if test "x" = "xyes"; then
Die
x
, zumindest für POSIX-kompatible Shells, ist tatsächlich redundant, da die Anführungszeichen ergeben, dass sowohl ein leeres Argument als auch ein Argument mit Leerzeichen als ein einzelnes Objekt interpretiert werden.quelle
test "$SHELL_VAR" = yes
eleganter lösen alsxyes
? Wäre eine Änderung der Reihenfolge'abc' = "$1"
für die Optionsverarbeitung eine weitere Option?test
verschwinden und nicht zu einer leeren Zeichenfolge werden? Behandeln verschiedene Muscheln dies unterschiedlich?export xxx=''
,if test $xxx = 1 ; then echo 2 ; fi
,export xxx='yyy'
,if test $xxx = 1 ; then echo 2 ; fi
. Der ersteif
gibt einen Fehler aus, der zweite nicht. Das ist inbash
.x
möglicherweise in älteren Muscheln verwendet wurde.Der andere Grund, den noch niemand erwähnt hat, betrifft die Optionsverarbeitung. Wenn Sie schreiben:
if [ "$1" = "abc" ]; then ...
und $ 1 hat den Wert '-n', die Syntax des Testbefehls ist mehrdeutig; Es ist nicht klar, was Sie getestet haben. Das 'x' an der Vorderseite verhindert, dass ein führender Armaturenbrett Probleme verursacht.
Sie müssen sich wirklich alte Muscheln ansehen, um eine zu finden, bei der der Testbefehl keine Unterstützung für
-n
oder hat-z
. Dertest
Befehl Version 7 (1978) enthielt sie. Es ist nicht ganz irrelevant - einige UNIX-Inhalte der Version 6 sind in BSD entkommen, aber heutzutage ist es äußerst schwierig, etwas zu finden, das im aktuellen Gebrauch so alt ist.Es ist gefährlich, keine doppelten Anführungszeichen um Werte zu verwenden, wie eine Reihe anderer Personen betonten. In der Tat, wenn die Möglichkeit besteht, dass Dateinamen Leerzeichen enthalten (MacOS X und Windows unterstützen dies in gewissem Maße, und Unix hat dies immer unterstützt, obwohl Tools wie
xargs
erschweren Sie es), dann sollten Sie Dateinamen jedes Mal in doppelte Anführungszeichen setzen, wenn Sie sie auch verwenden. Wenn Sie nicht für den Wert verantwortlich sind (z. B. während der Optionsbehandlung und die Variable beim Start auf "Nein" und beim Einfügen eines Flags in die Befehlszeile auf "Ja" setzen), ist es nicht sicher, nicht zitierte Formen von Variablen zu verwenden bis Sie sie als sicher erwiesen haben - und Sie können es genauso gut die ganze Zeit für viele Zwecke tun. Oder dokumentieren Sie, dass Ihre Skripte schrecklich fehlschlagen, wenn Benutzer versuchen, Dateien mit Leerzeichen in den Namen zu verarbeiten. (Und es gibt noch andere Charaktere, über die man sich Sorgen machen muss - Backticks könnten zum Beispiel auch ziemlich böse sein.)quelle
test
Implementierung sollte daher nicht in den Verzweigungsfall [-n "$ var"] eingehen (für den nur 2 Argumente erforderlich sind). Persönlich gab es jedes Mal, wenn ich Probleme hatte, entweder fehlende Anführungszeichen um $ var, was zu dem Fehler "=: unärer Operator erwartet" führte, oder die Option -z nicht vorhanden oder eine komplexe Verwendungtest
innerhalb [...] des Kerns anstelle von mit mehreren [test1] || [test2] auf Shell-Ebene (wie @Jay erwähnt).test
bizarre Dinge getan, und die Technik war gegen diese bizarren Implementierungen geschützt. Vielleicht haben Sie das Glück, sich heutzutage keine Sorgen mehr machen zu müssen.Es gibt zwei Gründe, die ich für diese Konvention kenne:
http://tldp.org/LDP/abs/html/comparison-ops.html
Zweitens existierten in anderen Shells als Bash, insbesondere in älteren, die Testbedingungen wie '-z' zum Testen auf eine leere Variable nicht.
if [ -z "$SOME_VAR" ]; then echo "this variable is not defined" fi
funktioniert in BASH einwandfrei. Wenn Sie die Portabilität in verschiedenen UNIX-Umgebungen anstreben, in denen Sie nicht sicher sein können, ob die Standard-Shell Bash ist und ob sie die Testbedingung -z unterstützt, ist es sicherer, das Formular zu verwenden, wenn [" x $ SOME_VAR "=" x "], da dies immer den beabsichtigten Effekt hat. Im Wesentlichen handelt es sich hierbei um einen alten Shell-Scripting-Trick zum Auffinden einer leeren Variablen, der auch heute noch aus Gründen der Abwärtskompatibilität verwendet wird, obwohl sauberere Methoden verfügbar sind.
quelle
[ -n "$string" ] || [ "$a" = "$b" ]
Ich empfehle stattdessen:
if test "yes" = "$SHELL_VAR"; then
da tut es mit dem hässlichen weg
x
und löst das Problem , indem erwähnt https://stackoverflow.com/a/174288/895245 , die$SHELL_VAR
mit beginnen können-
und als Option gelesen werden.quelle
Ich glaube es liegt an
SHELLVAR=$(true) if test $SHELLVAR = "yes" ; then echo "yep" ; fi # bash: test: =: unary operator expected
ebenso gut wie
if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi # bash: test: =: unary operator expected
und
SHELLVAR=" hello" if test $SHELLVAR = "hello" ; then echo "yep" ; fi # yep
Dies sollte jedoch normalerweise funktionieren
SHELLVAR=" hello" if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi #<no output>
Aber wenn es sich irgendwo anders in der Ausgabe beschwert, ist es schwer zu sagen, worüber es sich beschwert, denke ich
SHELLVAR=" hello" if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi
funktioniert genauso gut, wäre aber einfacher zu debuggen.
quelle
Ich habe das unter DOS gemacht, wenn SHELL_VAR möglicherweise undefiniert ist.
quelle
Wenn Sie das "x $ SHELL_VAR" -Ding nicht ausführen, wird bei $ SHELL_VAR eine Fehlermeldung angezeigt, dass "=" kein monadischer Operator oder ähnliches ist.
quelle
x$FOO
nicht behoben werden können.