Meine Frage kommt von: Wie vermeidet das Speichern des regulären Ausdrucks in einer Shell-Variablen Probleme beim Zitieren von Sonderzeichen für die Shell? .
Warum liegt ein Fehler vor:
$ [[ $a = a|b ]] bash: syntax error in conditional expression: unexpected token `|' bash: syntax error near `|b'
Innerhalb
[[ ... ]]
des zweiten Operanden von=
wird erwartet, dass es sich um ein globales Muster handelt.Ist
a|b
kein gültiges Globbing-Muster? Können Sie angeben, gegen welche Syntaxregel verstoßen wird?In einigen Kommentaren wird darauf hingewiesen, dass dies
|
als Pipe interpretiert wird.Ändern Sie dann das
=
Glob-Muster in=~
Regex-Muster, um die|
Arbeit zu beginnen$ [[ $a =~ a|b ]]
Ich habe in meinem vorherigen Beitrag von Learning Bash p180 gelernt, dass zu Beginn der Interpretation als Pipe erkannt wurde, noch bevor andere Interpretationsschritte durchgeführt wurden (einschließlich der Analyse der bedingten Ausdrücke in den Beispielen). Also, wie kann als Regex-Operator bei der Verwendung erkannt werden
|
|
=~
, ohne bei ungültiger Verwendung als Pipe erkannt zu werden, genau wie bei der Verwendung=
? Das lässt mich denken, dass der Syntaxfehler in Teil 1 nicht bedeutet, dass er|
als Pipe interpretiert wird.Jede Zeile, die die Shell aus der Standardeingabe oder einem Skript liest, wird als Pipeline bezeichnet. Es enthält einen oder mehrere Befehle, die durch null oder mehrere Pipe-Zeichen (|) getrennt sind. Für jede gelesene Pipeline teilt die Shell sie in Befehle auf, richtet die E / A für die Pipeline ein und führt dann für jeden Befehl die folgenden Schritte aus (Abbildung 7-1):
Vielen Dank.
|
Besonderes ist) standardmäßig rechts von aktiviert ist[[ $var = $pattern ]]
. Es wäre interessant, die Versionen undshopt
Optionskonfigurationen zu isolieren, bei denen dieses Verhalten auftritt. Wenn nur diejenigenextglob
aktiviert sind, die entweder standardmäßig oder explizit konfiguriert sind, sind wir hier.pattern='a|b'
und erweitern Sie dann$pattern
unquoted auf dem RHS.Antworten:
Es gibt keinen guten Grund warum
Sollte einen Fehler melden, anstatt zu testen, ob $ a die
a|b
Zeichenfolge ist[[ $a =~ a|b ]]
kein Fehler zurückgegeben wird.Der einzige Grund ist, dass
|
im Allgemeinen (außen und innen[[ ... ]]
) ein besonderer Charakter ist. Erwarten Sie an dieser[[ $a =
Stellebash
einen Tokentyp, der ein normales WORT ist, wie die Argumente oder Ziele von Umleitungen in einer normalen Shell-Befehlszeile (aber so, als ob dieextglob
Option seit Bash 4.1 aktiviert worden wäre).(Mit WORD beziehe ich mich hier auf ein Wort in einer hypothetischen Shell-Grammatik, wie sie in der POSIX-Spezifikation beschrieben ist. Dies ist etwas, das die Shell als ein Token in einer einfachen Shell-Befehlszeile parsen würde, nicht als andere Definition von Wörtern wie dem Englischen eine aus einer Folge von Buchstaben oder eine Sequenz von nicht-Abstandszeichen.
foo"bar baz"
,$(echo x y)
sind zwei solcher WORD s).In einer normalen Shell-Befehlszeile:
Wird
echo a
zu geleitetb
.a|b
ist kein WORT , es sind drei Token: eina
WORT , ein|
Token und einb
WORT- Token.Wenn in verwendet
[[ $a = a|b ]]
,bash
rechnet mit einem WORD , die es bekommt (a
), aber dann findet ein unerwartetes|
Token , das den Fehler verursacht.Interessanterweise
bash
beschwert sich nicht in:Da es sich jetzt um ein
a
Token handelt, auf das ein||
Token folgtb
, wird es folgendermaßen analysiert:Was testet das
$a
ista
oder dass dieb
Zeichenfolge nicht leer ist.Jetzt in:
bash
kann nicht die gleiche Parsing-Regel haben. Dieselbe Parsing-Regel zu haben würde bedeuten, dass das oben Genannte einen Fehler ergibt und dass man dies zitieren muss,|
um sicherzustellen, dass es sich uma|b
ein einziges WORT handelt . Aber seit Bash 3.2, wenn Sie tun:Das
a|b
passt nicht mehr zum regulären Ausdruck, sondern zuma\|b
regulären Ausdruck. Das heißt, Shell-Anführungszeichen haben den Nebeneffekt, dass die spezielle Bedeutung von regulären Ausdrücken entfernt wird. Es ist eine Funktion, daher ähnelt das Verhalten[[ $a = "?" ]]
demjenigen, aber Platzhaltermuster (verwendet in[[ $a = pattern ]]
) sind Shell- WÖRTER (verwendet zum Beispiel in Globs), während reguläre Ausdrücke dies nicht tun.So müssen
bash
alle erweiterten Regexp-Operatoren, die ansonsten normalerweise spezielle Shell-Zeichen|
sind(
,)
unterschiedlich behandelt werden, wenn ein Argument der=~
Operators .Beachten Sie jedoch, dass während
jetzt arbeitet,
nicht. Du brauchst:
Welche in früheren Versionen von
bash
würde falsch auf Backslash passen. Das war behoben, aberStimmt nicht mit Backslash überein, wie es zum Beispiel sein sollte. Da sich das
bash
nicht in)
den Klammern befindet, entgeht das)
, was zu einem[^]\)]
regulären Ausdruck führt, der für jedes Zeichen außer]
,\
und passt)
.ksh93
hat viel schlimmere Bugs an dieser Front.In
zsh
, es ist eine normale Shell Wort , das erwartet wird , und unter Angabe regexp Betreiber nicht die Bedeutung von regexp Operatoren beeinflussen.Stimmt mit dem
a|b
regulären Ausdruck überein.Das heißt, das
=~
kann auch zum[
/test
Befehl hinzugefügt werden :(auch arbeiten in
yash
. Die=~
muss dortzsh
als=something
spezieller Shell-Operator angegeben werden).Bash 3.1 verwendet, um sich wie zu verhalten
zsh
. Es wurde in Version 3.2 geändert, vermutlich, um eine Ausrichtung mitksh93
(obwohlbash
es sich um die erste Shell handelte[[ =~ ]]
), aber Sie können es trotzdem tunBASH_COMPAT=31
odershopt -s compat31
zum vorherigen Verhalten zurückkehren (mit der Ausnahme, dass[[ $a =~ a|b ]]
inbash
Version 3.1 zwar ein Fehler zurückgegeben wird , dies jedoch nicht mehr der Fall ist inbash -O compat31
neueren Versionen vonbash
).Ich hoffe, es wird klargestellt, warum ich sagte, dass die Regeln verwirrend waren und warum:
Hilft auch bei der Portabilität auf andere Shells.
quelle
[[ $a = a|b ]]
.a|b
ist kein Shell WORD hier, es ist dasa
,|
undb
Token. Wieecho a|b
nicht ausgibta|b
oder sich nicht ausdehnt , einea|b
glob, müssen Sie das zitieren ,|
da es eine spezielle Shell - Charakter ist , die in diesem Zusammenhang ist ungültig.[[ $a = (a|b) ]]
würde funktionieren wieecho (a|b)
würde funktionieren wie(a|b)
ein zsh-Wildcard-Operator.Standard Klackse ( "Dateiname Erweiterung") sind:
*
,?
und[ ... ]
.|
ist in den Standardeinstellungen (non-extglob) kein gültiger Glob-Operator.Versuchen:
quelle
|
buchstäblich inteperiert? Warum liegt ein Syntaxfehler vor?|
Ist ein Glob-Operator in der Standardeinstellung nicht so, dass er nicht|
ohne Anführungszeichen wörtlich interpretiert wird? Warum liegt also ein Syntaxfehler vor?|
ist ein Steuerzeichen; Es wird niemals wie ein Buchstabe oder eine Zahl als buchstäbliches Zeichen behandelt.[[ $a = a
ist kein gültiger Befehl, dessen Ausgabe an einen anderen Prozess weitergeleitet werden kann (zumindest dachte die Shell, dass Sie das versucht haben).Wenn Sie eine Regex-Übereinstimmung wünschen, wäre der Test:
quelle