Antworten:
KURZE ANTWORT
Wie andere gesagt haben - Sie sollten immer die Variablen zitieren, um seltsames Verhalten zu verhindern. Also benutze echo "$ foo" in anstatt nur echo $ foo .
LANGE ANTWORT
Ich denke, dieses Beispiel verdient weitere Erklärung, da mehr los ist, als es auf den ersten Blick erscheinen mag.
Ich kann sehen, wo Ihre Verwirrung ins Spiel kommt, denn nachdem Sie Ihr erstes Beispiel ausgeführt haben, haben Sie sich wahrscheinlich gedacht, dass die Shell offensichtlich Folgendes tut:
Also von Ihrem ersten Beispiel:
me$ FOO="BAR * BAR"
me$ echo $FOO
Nach Parametererweiterung entspricht:
me$ echo BAR * BAR
Und nach Dateinamenerweiterung ist gleichbedeutend mit:
me$ echo BAR file1 file2 file3 file4 BAR
Und wenn Sie nur tippen echo BAR * BAR
in die Befehlszeile eingeben, werden Sie sehen, dass sie gleichwertig sind.
Sie haben sich also wahrscheinlich gedacht: "Wenn ich dem * entkomme, kann ich die Dateinamenerweiterung verhindern."
Also aus Ihrem zweiten Beispiel:
me$ FOO="BAR \* BAR"
me$ echo $FOO
Nach der Parametererweiterung sollte äquivalent sein zu:
me$ echo BAR \* BAR
Und nach der Dateinamenerweiterung sollte gleichbedeutend sein mit:
me$ echo BAR \* BAR
Und wenn Sie versuchen, "echo BAR \ * BAR" direkt in die Befehlszeile einzugeben, wird tatsächlich "BAR * BAR" ausgegeben, da die Dateinamenerweiterung durch das Escape verhindert wird.
Warum hat die Verwendung von $ foo nicht funktioniert?
Dies liegt daran, dass eine dritte Erweiterung stattfindet - das Entfernen von Angeboten. Aus der Bash-manuellen Angebotsentfernung geht Folgendes hervor:
Nach den vorhergehenden Erweiterungen werden alle nicht zitierten Vorkommen der Zeichen '\', '' 'und' "'entfernt, die nicht aus einer der oben genannten Erweiterungen resultiert haben.
Wenn Sie den Befehl direkt in die Befehlszeile eingeben, ist das Escape-Zeichen nicht das Ergebnis einer vorherigen Erweiterung. BASH entfernt es also, bevor es an den Echo-Befehl gesendet wird. Im zweiten Beispiel war das "\ *" das Ergebnis einer vorherigen Parametererweiterung, daher wird es NICHT entfernt. Infolgedessen erhält das Echo "\ *" und druckt es aus.
Beachten Sie den Unterschied zwischen dem ersten Beispiel - "*" ist nicht in den Zeichen enthalten, die durch Entfernen von Anführungszeichen entfernt werden.
Ich hoffe das macht Sinn. Am Ende die Schlussfolgerung in der gleichen - verwenden Sie einfach Anführungszeichen. Ich dachte nur, ich würde erklären, warum Escape, was logischerweise funktionieren sollte, wenn nur die Erweiterung von Parameter und Dateiname im Spiel ist, nicht funktioniert.
Eine vollständige Erläuterung der BASH-Erweiterungen finden Sie unter:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions
Ich werde diesem alten Thread etwas hinzufügen.
Normalerweise würden Sie verwenden
$ echo "$FOO"
Ich hatte jedoch auch mit dieser Syntax Probleme. Betrachten Sie das folgende Skript.
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"
Die *
müssen wörtlich weitergegeben werden curl
, aber die gleichen Probleme werden auftreten. Das obige Beispiel funktioniert nicht (es wird auf Dateinamen im aktuellen Verzeichnis erweitert) und auch nicht \*
. Sie können auch nicht zitieren, $curl_opts
da dies als einzelne (ungültige) Option für erkannt wird curl
.
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
Daher würde ich die Verwendung der bash
Variablen empfehlen $GLOBIGNORE
, um die Dateinamenerweiterung insgesamt zu verhindern, wenn sie auf das globale Muster angewendet wird, oder das set -f
integrierte Flag verwenden.
#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1" ## no filename expansion
Anwendung auf Ihr ursprüngliches Beispiel:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
me$ set -f
me$ echo $FOO
BAR * BAR
me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR
SELECT * FROM etc.
, dass dies der einzige Weg ist, der funktioniert.
FOO='BAR * BAR'
echo "$FOO"
echo "$FOO"
Es kann sich lohnen, sich daran zu gewöhnen, printf
eher als echo
auf der Kommandozeile zu verwenden.
In diesem Beispiel bietet es nicht viel Nutzen, kann aber bei komplexeren Ausgaben nützlicher sein.
FOO="BAR * BAR"
printf %s "$FOO"