Ich möchte feststellen, ob eine mehrzeilige Zeichenfolge mit einer Zeile endet, die ein bestimmtes Muster enthält.
Dieser Code ist fehlgeschlagen, er stimmt nicht überein.
s=`echo hello && echo world && echo OK`
[[ "$s" =~ 'OK$' ]] && echo match
Akzeptierte Antwort:
In bash
3.2 oder höher und wenn die Kompatibilität zu 3.1 nicht aktiviert ist (mit dem compat31
Option oder BASH_COMPAT=3.1
), Zitieren regulärer Ausdrucksoperatoren (nicht nur mit aber mit einem der
bash
Anführungszeichen ('...'
, "..."
, $'...'
, $"..."
)) ihre besondere Bedeutung entfernt.
[[ $var =~ 'OK$' ]]
Übereinstimmungen nur in Zeichenfolgen, die OK$
enthalten wörtlich (dass $
entspricht einem wörtlichen $
)
[[ $var =~ OK$ ]]
Übereinstimmungen mit Zeichenfolgen, die auf OK
enden (das $
ist der RE-Operator, der am Ende der Zeichenfolge passt).
Das gilt auch für in Variablen gespeicherte reguläre Ausdrücke oder das Ergebnis einer Substitution.
[[ $var =~ $regexp ]] # $var matches $regexp
[[ $var =~ "$string" ]] # $var contains $string
Beachten Sie, dass es umständlich werden kann, da es einige Zeichen gibt, die Sie für die Shell-Syntax in Anführungszeichen setzen müssen (wie Leerzeichen, <
, >
, &
, Klammern, wenn nicht übereinstimmend). Wenn Sie beispielsweise mit .{3} <> [)}]&
übereinstimmen möchten Regexp (3 Zeichen gefolgt von einem " <> "
, entweder ein )
oder }
und ein &
), brauchen Sie so etwas wie:
[[ $var =~ .{3}" <> "[})]& ]]
Wenn Sie Zweifel haben, welche Zeichen in Anführungszeichen gesetzt werden müssen, können Sie immer eine temporäre Variable verwenden. Das bedeutet auch, dass der Code mit bash31
kompatibel wird , zsh
oder ksh93
:
pattern='.{3} <> [})]&'
[[ $var =~ $pattern ]] # remember *not* to quote $pattern here
Das ist auch der einzige Weg (abgesehen von der Verwendung des compat31
Option (oder BASH_COMPAT=3.1
)) können Sie die erweiterten Nicht-POSIX-Operatoren der regulären Ausdrücke Ihres Systems verwenden.
Zum Beispiel für <
Um als Wortgrenze behandelt zu werden, was in vielen Regexp-Engines der Fall ist, benötigen Sie:
pattern='<word>'
[[ $var =~ $pattern ]]
Tun:
[[ $var =~ <word> ]]
funktioniert nicht als bash
behandelt diese als Shell-Quoting-Operatoren und entfernen Sie sie, bevor Sie
<word>
übergeben in die Regexp-Bibliothek.
Beachten Sie, dass es in ksh93 viel schlimmer ist, wo:
[[ $var =~ "x.*$" ]]
wird zum Beispiel auf whatever-xa*
passen aber nicht whatever-xfoo
. Das obige Zitieren entfernt die besondere Bedeutung von *
, aber nicht zu .
noch $
.
Die zsh
Das Verhalten ist einfacher:Anführungszeichen ändern dort nicht die Bedeutung von Regexp-Operatoren (wie in bash31), was zu einem vorhersehbareren Verhalten führt (es kann auch PCRE-Regexps anstelle von ERE verwenden (mit set -o rematchpcre
). )).
yash
hat keinen [[...]]
konstruieren, aber sein [
builtin hat ein =~
Operator (auch in zsh
). Und natürlich [
Da es sich um einen normalen Befehl handelt, kann das Zitieren die Art und Weise, wie Regexp-Operatoren interpretiert werden, nicht beeinflussen.
Beachten Sie auch, dass genau genommen Ihr $s
enthält nicht 3 Zeilen, sondern 2 volle Zeilen gefolgt von einer nicht abgeschlossenen Zeile. Es enthält hellonworldnOK
. Im OK$
erweiterter regulärer Ausdruck, der $
-Operator würde nur am Ende der Zeichenfolge übereinstimmen .
In einem dreizeiligen String , wie hellonworldnOKn
(was Sie mit der Befehlsersetzung nicht erreichen könnten, da die Befehlsersetzung all entfernt abschließende Zeilenumbrüche), das $
würde nach dem n
passen , also OK$
würde nicht übereinstimmen.
Mit zsh -o pcrematch
jedoch das $
Übereinstimmungen sowohl am Ende der Zeichenfolge als auch vor dem Zeilenumbruch am Ende der Zeichenfolge, falls vorhanden, da sie den PCRE_DOLLAR_ENDONLY
nicht passieren Flag zu pcre_compile
. Dies könnte als schlechte Idee angesehen werden, da Variablen in Shells im Allgemeinen kein abschließendes Zeilenumbruchzeichen enthalten, und wenn sie dies tun, möchten wir sie im Allgemeinen als Daten betrachten.