Bash-Test: Was macht "= ~"?

40
#!/bin/bash
INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then

echo "INT is an integer."

else

echo "INT is not an integer." >&2

exit 1

fi

Was macht das Leading ~im beginnenden regulären Ausdruck?

Ragnarok
quelle
3
Es ist kein
regulärer Ausdruck
5
Hast du das Bash-Handbuch gelesen? Was finden Sie unklar?
Ikarus
3
Durchsuchen Sie die bash-Manpage nach = ~
Jeff Schaller

Antworten:

46

Tatsächlich ~ist The Teil des Operators =~, der eine Übereinstimmung des Strings mit regulären Ausdrücken links und rechts vom erweiterten regulären Ausdruck ausführt.

[[ "string" =~ pattern ]]

Beachten Sie, dass die Zeichenfolge in Anführungszeichen gesetzt und der reguläre Ausdruck nicht in Anführungszeichen gesetzt werden sollte.

Ein ähnlicher Operator wird in der Programmiersprache Perl verwendet.

Die regulären Ausdrücke, die unter verstanden werden, bashsind die gleichen, die GNU grepmit dem -EFlag versteht, dh die erweiterte Menge regulärer Ausdrücke.


Etwas abseits des Themas, aber gut zu wissen:

Beim Abgleichen mit einem regulären Ausdruck, der Erfassungsgruppen enthält, ist der von jeder Gruppe erfasste Teil der Zeichenfolge im BASH_REMATCHArray verfügbar . Die nullte / erster Eintrag in dieser Matrix entspricht &im Ersetzungsmuster sed‚s Substitutionsbefehls (oder $&in Perl), welche das Bit des String ist, der das Muster übereinstimmt, während die Einträge mit dem Index 1 und weiter entsprechen \1, \2usw. . in einem sedErsetzungsmuster (oder $1, $2usw. in Perl), dh die von jeder Klammer angepasst Bits.

Beispiel:

string=$( date +%T )

if [[ "$string" =~ ^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$ ]]; then
  printf 'Got %s, %s and %s\n' \
    "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
fi

Dies kann ausgegeben werden

Got 09, 19 and 14

wenn die aktuelle Zeit zufällig 09:19:14 ist.

Das REMATCHBit des BASH_REMATCHArraynamens stammt von "Regular Expression Match", dh "RE-Match".


In nicht- bashBourne-ähnlichen Shells kann auch eine expreingeschränkte Übereinstimmung mit regulären Ausdrücken verwendet werden (wobei nur grundlegende reguläre Ausdrücke verwendet werden).

Ein kleines Beispiel:

$ string="hello 123 world"
$ expr "$string" : ".*[^0-9]\([0-9][0-9]*\)"
123
Kusalananda
quelle
2
Es ist dasselbe wie das, was grep -Enur auf GNU-Systemen verstanden wird und nur, wenn eine Variable ohne Anführungszeichen als Muster verwendet wird [[ $var = $pattern ]](siehe [[ 'a b' =~ a\sb ]]vs p='a\sb'; [[ 'a b' =~ $p ]]). Beachten Sie auch, dass Shell-Anführungszeichen die Bedeutung von RE-Operatoren beeinflussen und dass einige Zeichen für die Shell-Token-Erstellung in Anführungszeichen gesetzt werden müssen, die sich auf die RE-Verarbeitung auswirken können. [[ '\' =~ [\/] ]]gibt false zurück. ksh93hat noch schlimmere Probleme. Siehe zsh(oder Bash 3.1) für einen vernünftigeren Ansatz, bei dem Shell- und RE-Anführungszeichen klar voneinander getrennt sind. Die [eingebauten zshund yashhaben auch einen =~Operator.
Stéphane Chazelas
2
sehr cool off-topic! +1 (
JJoao
@ StéphaneChazelas Wie ist es "saner", dass beide von diesem Spiel in zsh ?: [[ "This is a fine mess." =~ T.........fin*es* ]]; [[ "This is a fine mess." =~ T.........fin\*es\* ]]. Oder stimmt das *auch mit einem Zitat überein? [[ "This is a fine mess." =~ "T.........fin*es*" ]].
Sorontar
Es ist vernünftiger (IMO), da es viel einfachere Regeln gibt. Shell-Quoting und RE-Escape sind klar voneinander getrennt. In [[ a =~ .* ]]oder [[ a =~ '.*' ]]oder [[ a =~ \.\* ]]wird dieselbe .*RE an den =~Operator übergeben. OTH, in bash, [[ '\' =~ [)] ]]gibt einen Fehler zurück, würden Sie wissen, ohne es zu versuchen, ob [[ '\' =~ [\)] ]]Übereinstimmungen vorliegen? Wie wäre es [[ '\' =~ [\/] ]](tut es in ksh93). Wie wäre es c='a-z'; [[ a =~ ["$c"] ]](vergleiche mit dem =Betreiber)? Siehe auch: [[ '\' =~ [^]"."] ]]was gibt false zurück ... Beachten Sie, dass Sie tun können , shopt -s compat31in bashdem bekommen zshVerhalten.
Stéphane Chazelas
zsh/ bash -o compat31‚S Verhalten [[ a =~ '.*' ]]ist auch im Einklang mit [ a '=~' '.*' ](für [Implementierungen , die Unterstützung =~) oder expr a : '.*'. OTOH, es ist nicht konsistent mit [[ a = '*' ]]vs [[ a = * ]](aber dann sind Globs Teil der Shell-Sprache, während REs nicht sind).
Stéphane Chazelas
4

Sie sollten die bash-Manpages unter dem [[ expression ]]Abschnitt lesen .

An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)).

Lange Rede kurzer Sinn, =~ist ein Operator, genau wie ==und !=. Es hat nichts mit dem tatsächlichen regulären Ausdruck in der Zeichenfolge zu seiner Rechten zu tun.

Sokel
quelle
Können Sie einige Beispiele finden, die den Einsatz in der Praxis demonstrieren =~...?
George Vasiliou
1
@GeorgeVasiliou Ich benutze es ziemlich oft in Skripten, die die Ausgabe eines Befehls in eine Variable setzen. Anschließend wird die Variable überprüft, um festzustellen, ob sie mit einem Zeichenfolgenmuster übereinstimmt. Dies ist zum Beispiel nützlich, wenn Sie eine Aktion basierend auf einer Fehlerausgabe dieses Befehls ausführen möchten.
Michael Martinez
@Sokel Für manche ist „RTFM“ leichter gesagt als getan. ⋯ man [[ expresssion ]]und man [[nichts zurück. help [[Gibt nützliche Informationen zurück - seit [[einem internen Bash-Befehl - aber sagt nicht, ob =~grundlegende oder erweiterte Regex-Syntax verwendet wird. ⋯ Der von Ihnen zitierte Text stammt aus der Bash- Manpage. Mir ist klar, dass Sie gesagt haben: "Lies die Manpages der Bash", aber zuerst dachte ich, Sie wollten die Manpages der Bash lesen. In jedem Fall wird man basheine riesige Datei zurückgegeben, die 4139 Zeilen (72 Seiten) lang ist. Es kann durch Drücken von gesucht werden /▒▒▒, was einen regulären Ausdruck erfordert, dessen Geschmack - wie =~- nicht spezifiziert ist.
Alex Quinn