it-swarm.com.de

Wie entkomme ich dem Platzhalter- / Sternchenzeichen in der Bash?

z.B.

me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR

und mit dem Escape-Zeichen "\":

me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR

Ich mache offensichtlich etwas Dummes.

Wie erhalte ich die Ausgabe "BAR * BAR"?

123
andyuk

Zitieren beim Setzen von $ FOO ist nicht genug. Sie müssen auch die Variablenreferenz angeben:

me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
121
finnw

KURZE ANTWORT

Wie andere bereits gesagt haben, sollten Sie die Variablen immer in Anführungszeichen setzen, um ungewöhnliches Verhalten zu vermeiden. Verwenden Sie also echo "$ foo" anstelle von nur echo $ foo.

LANGE ANTWORT

Ich denke, dass dieses Beispiel weitere Erklärungen verdient, da mehr vor sich geht, als es auf den ersten Blick erscheinen mag.

Ich kann sehen, wo Ihre Verwirrung hereinkommt, denn nachdem Sie Ihr erstes Beispiel ausgeführt haben, haben Sie sich wahrscheinlich gedacht, dass die Shell offensichtlich Folgendes tut:

  1. Parametererweiterung
  2. Dateinamenerweiterung

Also von Ihrem ersten Beispiel:

me$ FOO="BAR * BAR"
me$ echo $FOO

Nach Parametererweiterung entspricht:

me$ echo BAR * BAR

Und nach der Dateinamenerweiterung ist äquivalent zu:

me$ echo BAR file1 file2 file3 file4 BAR

Und wenn Sie nur echo BAR * BAR In der Befehlszeile sehen Sie, dass sie gleichwertig sind.

Also haben Sie sich wahrscheinlich gedacht: "Wenn ich dem * entkomme, kann ich die Dateinamenerweiterung verhindern."

Also von Ihrem zweiten Beispiel:

me$ FOO="BAR \* BAR"
me$ echo $FOO

Nach Parametererweiterung sollte gleichbedeutend sein mit:

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 "BAR * BAR" ausgegeben, da die Dateinamenerweiterung durch das Escape verhindert wird.

Warum hat $ foo nicht funktioniert?

Das liegt daran, dass es eine dritte Erweiterung gibt - das Entfernen von Zitaten. Aus der Bash-Anleitung zum manuellen Entfernen von Zitaten geht Folgendes hervor:

Nach den vorhergehenden Erweiterungen werden alle nicht zitierten Vorkommen der Zeichen "\", "" "und" "entfernt, die nicht aus einer der obigen Erweiterungen resultierten.

Wenn Sie also den Befehl direkt in die Befehlszeile eingeben, ist das Escape-Zeichen nicht das Ergebnis einer vorherigen Erweiterung. Daher entfernt BASH es, bevor es an den Echo-Befehl gesendet wird. Im zweiten Beispiel war es jedoch "\ *" Das Ergebnis einer vorherigen Parametererweiterung, wird also NICHT entfernt. Als Ergebnis erhält das Echo "\ *" und das wird gedruckt.

Beachten Sie den Unterschied zwischen dem ersten Beispiel - "*" ist nicht in den Zeichen enthalten, die durch das 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 die Escape-Funktion, die logischerweise funktionieren sollte, wenn nur die Parameter- und Dateinamenerweiterung aktiv 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

96
mithu

Ich werde ein bisschen zu diesem alten Thread hinzufügen.

Normalerweise würden Sie verwenden

$ echo "$FOO"

Trotzdem hatte ich Probleme mit dieser Syntax. Betrachten Sie das folgende Skript.

#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"

Der * Muss wörtlich an curl übergeben werden, es treten jedoch dieselben Probleme auf. Das obige Beispiel funktioniert nicht (es wird auf Dateinamen im aktuellen Verzeichnis erweitert) und auch nicht \*. Sie können auch nicht $curl_opts Angeben, da dies als einzelne (ungültige) Option für curl erkannt wird.

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 -Variable $GLOBIGNORE Empfehlen, um eine Dateinamenerweiterung zu verhindern, wenn sie auf das globale Muster angewendet wird, oder das integrierte Flag set -f Verwenden.

#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"  ## no filename expansion

Anwenden 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
47
AlexandreH
FOO='BAR * BAR'
echo "$FOO"
4
tzot

Es kann sich lohnen, sich daran zu gewöhnen, printf anstelle von echo in der Befehlszeile zu verwenden.

In diesem Beispiel bietet es keinen großen Nutzen, kann aber bei komplexeren Ausgaben nützlicher sein.

FOO="BAR * BAR"
printf %s "$FOO"
3
Dave Webb
echo "$FOO"
3
Rafał Dowgird