Bash Regex mit Anführungszeichen?


77

Der folgende Code

number=1
if [[ $number =~ [0-9] ]]
then
  echo matched
fi

funktioniert. Wenn ich jedoch versuche, Anführungszeichen in der Regex zu verwenden, hört es auf:

number=1
if [[ $number =~ "[0-9]" ]]
then
  echo matched
fi

Ich habe es auch versucht "\[0-9\]". Was vermisse ich?

Witzigerweise schlägt Bash Advanced Scripting Guide vor, dass dies funktionieren sollte.

Bash Version 3.2.39.


4
Das ABS ist als Quelle für ungenaue (oder an besseren Tagen lediglich irreführende) Leitlinien eher berüchtigt. Betrachten Sie es als die W3Schools des Shell-Scripting. Betrachten Sie die Wikis bash-hackers.org oder Wooledge als Alternativen, die im Hinblick auf Genauigkeit beibehalten werden.
Charles Duffy

Antworten:


116

Es wurde zwischen 3.1 und 3.2 geändert . Vermutlich benötigt die erweiterte Anleitung ein Update.

Dies ist eine knappe Beschreibung der neuen Funktionen, die seit der Veröffentlichung von bash-3.1 zu bash-3.2 hinzugefügt wurden. Wie immer ist die Handbuchseite (doc / bash.1) der Ort, an dem Sie nach vollständigen Beschreibungen suchen können.

  1. Neue Funktionen in Bash

schnipsen

f. Das Zitieren des Zeichenfolgenarguments für den Operator [[Befehl = ~] erzwingt jetzt den Zeichenfolgenabgleich wie bei den anderen Operatoren für den Mustervergleich.

Leider wird das vorhandene Zitat mithilfe von Skripten unterbrochen, es sei denn, Sie hatten die Möglichkeit, Muster in Variablen zu speichern und sie anstelle der regulären Ausdrücke direkt zu verwenden. Beispiel unten.

$ bash --version
GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
$ number=2
$ if [[ $number =~ "[0-9]" ]]; then echo match; fi
$ if [[ $number =~ [0-9] ]]; then echo match; fi
match
$ re="[0-9]"
$ if [[ $number =~ $re ]]; then echo MATCH; fi
MATCH

$ bash --version
GNU bash, version 3.00.0(1)-release (i586-suse-linux)
Copyright (C) 2004 Free Software Foundation, Inc.
$ number=2
$ if [[ $number =~ "[0-9]" ]]; then echo match; fi
match
$ if [[ "$number" =~ [0-9] ]]; then echo match; fi
match

16
Das macht echt Spaß. Zitierte Regexe funktionieren nicht mehr. Nicht zitierte reguläre Ausdrücke mit Leerzeichen funktionieren nicht. Variablenbasierte reguläre Ausdrücke funktionieren auch dann, wenn sie Leerzeichen enthalten. Was für ein Chaos.
Pavel Šimerda

21

In Bash 3.2 wurde eine Kompatibilitätsoption compatible31 eingeführt, die das Zitierverhalten von Bash-regulären Ausdrücken auf 3.1 zurücksetzt

Ohne Kompatibilität31:

$ shopt -u compat31
$ shopt compat31
compat31        off
$ set -x
$ if [[ "9" =~ "[0-9]" ]]; then echo match; else echo no match; fi
+ [[ 9 =~ \[0-9] ]]
+ echo no match
no match

Mit kompatibel31:

$ shopt -s compat31
+ shopt -s compat31
$ if [[ "9" =~ "[0-9]" ]]; then echo match; else echo no match; fi
+ [[ 9 =~ [0-9] ]]
+ echo match
match

Link zum Patch: http://ftp.gnu.org/gnu/bash/bash-3.2-patches/bash32-039


7

GNU Bash, Version 4.2.25 (1) -Veröffentlichung (x86_64-pc-linux-gnu)

Einige Beispiele für String-Match und Regex-Match

    $ if [[ 234 =~ "[0-9]" ]]; then echo matches;  fi # string match
    $ 

    $ if [[ 234 =~ [0-9] ]]; then echo matches;  fi # regex natch 
    matches


    $ var="[0-9]"

    $ if [[ 234 =~ $var ]]; then echo matches;  fi # regex match
    matches


    $ if [[ 234 =~ "$var" ]]; then echo matches;  fi # string match after substituting $var as [0-9]

    $ if [[ 'rss$var919' =~ "$var" ]]; then echo matches;  fi   # string match after substituting $var as [0-9]

    $ if [[ 'rss$var919' =~ $var ]]; then echo matches;  fi # regex match after substituting $var as [0-9]
    matches


    $ if [[ "rss\$var919" =~ "$var" ]]; then echo matches;  fi # string match won't work

    $ if [[ "rss\\$var919" =~ "$var" ]]; then echo matches;  fi # string match won't work


    $ if [[ "rss'$var'""919" =~ "$var" ]]; then echo matches;  fi # $var is substituted on LHS & RHS and then string match happens 
    matches

    $ if [[ 'rss$var919' =~ "\$var" ]]; then echo matches;  fi # string match !
    matches



    $ if [[ 'rss$var919' =~ "$var" ]]; then echo matches;  fi # string match failed
    $ 

    $ if [[ 'rss$var919' =~ '$var' ]]; then echo matches;  fi # string match
    matches



    $ echo $var
    [0-9]

    $ 

    $ if [[ abc123def =~ "[0-9]" ]]; then echo matches;  fi

    $ if [[ abc123def =~ [0-9] ]]; then echo matches;  fi
    matches

    $ if [[ 'rss$var919' =~ '$var' ]]; then echo matches;  fi # string match due to single quotes on RHS $var matches $var
    matches


    $ if [[ 'rss$var919' =~ $var ]]; then echo matches;  fi # Regex match 
    matches
    $ if [[ 'rss$var' =~ $var ]]; then echo matches;  fi # Above e.g. really is regex match and not string match
    $


    $ if [[ 'rss$var919[0-9]' =~ "$var" ]]; then echo matches;  fi # string match RHS substituted and then matched
    matches

    $ if [[ 'rss$var919' =~ "'$var'" ]]; then echo matches;  fi # trying to string match '$var' fails


    $ if [[ '$var' =~ "'$var'" ]]; then echo matches;  fi # string match still fails as single quotes are omitted on RHS 

    $ if [[ \'$var\' =~ "'$var'" ]]; then echo matches;  fi # this string match works as single quotes are included now on RHS
    matches

5

Wie in anderen Antworten erwähnt, ist das Einfügen des regulären Ausdrucks in eine Variable ein allgemeiner Weg, um Kompatibilität über verschiedene zu erreichen Versionen. Sie können diese Problemumgehung auch verwenden, um dasselbe zu erreichen, während Sie Ihren regulären Ausdruck innerhalb des bedingten Ausdrucks halten:

$ number=1
$ if [[ $number =~ $(echo "[0-9]") ]]; then echo matched; fi
matched
$ 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.