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.