Es gibt keinen guten Grund warum
[[ $a = a|b ]]
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 =
Stelle bash
einen Tokentyp, der ein normales WORT ist, wie die Argumente oder Ziele von Umleitungen in einer normalen Shell-Befehlszeile (aber so, als ob die extglob
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:
echo a|b
Wird echo a
zu geleitet b
. a|b
ist kein WORT , es sind drei Token: ein a
WORT , ein |
Token und ein b
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:
[[ $a = a||b ]]
Da es sich jetzt um ein a
Token handelt, auf das ein ||
Token folgt b
, wird es folgendermaßen analysiert:
[[ $a = a || b ]]
Was testet das $a
ist a
oder dass die b
Zeichenfolge nicht leer ist.
Jetzt in:
[[ $a =~ a|b ]]
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 um a|b
ein einziges WORT handelt . Aber seit Bash 3.2, wenn Sie tun:
[[ $a =~ 'a|b' ]]
Das a|b
passt nicht mehr zum regulären Ausdruck, sondern zum a\|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
[[ $a =~ (ab)*c ]]
jetzt arbeitet,
[[ $a =~ [)}] ]]
nicht. Du brauchst:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
Welche in früheren Versionen von bash
würde falsch auf Backslash passen. Das war behoben, aber
[[ $a =~ [^]')'] ]]
Stimmt 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.
[[ $a =~ 'a|b' ]]
Stimmt mit dem a|b
regulären Ausdruck überein.
Das heißt, das =~
kann auch zum [
/ test
Befehl hinzugefügt werden :
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(auch arbeiten in yash
. Die =~
muss dort zsh
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 mit ksh93
(obwohl bash
es sich um die erste Shell handelte [[ =~ ]]
), aber Sie können es trotzdem tun BASH_COMPAT=31
oder shopt -s compat31
zum vorherigen Verhalten zurückkehren (mit der Ausnahme, dass [[ $a =~ a|b ]]
in bash
Version 3.1 zwar ein Fehler zurückgegeben wird , dies jedoch nicht mehr der Fall ist in bash -O compat31
neueren Versionen von bash
).
Ich hoffe, es wird klargestellt, warum ich sagte, dass die Regeln verwirrend waren und warum:
[[ $a =~ $var ]]
Hilft auch bei der Portabilität auf andere Shells.
|
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.