Reguläre Ausdrücke in einfachen Anführungszeichen – verlieren sie ihren Wert?

Reguläre Ausdrücke in einfachen Anführungszeichen – verlieren sie ihren Wert?

In dem Buch, das ich gerade lese – Learning the Bash Shell von O'Reilly – wird der Code wie folgt spezifiziert:

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

   howmany=$1

   shift
   ....
   ....
   etc

Dabei wird das grepSuchdienstprogramm verwendet, um zu testen, ob $1es mit dem entsprechenden Muster übereinstimmt. Dazu stellen wir ^-[0-9][0-9]*$grep den regulären Ausdruck zur Verfügung, der als „ein anfänglicher Bindestrich gefolgt von einer Ziffer, optional gefolgt von einer oder mehreren Ziffern“ interpretiert wird. Wenn eine Übereinstimmung gefunden wird, grepwird die Übereinstimmung zurückgegeben und der Test ist wahr, andernfalls grepwird nichts zurückgegeben und die Verarbeitung wird mit dem Test fortgesetzt elif.

Beachten Sie, dass wir den regulären Ausdruck in einfache Anführungszeichen eingeschlossen haben, um zu verhindern, dass die Shell das $ und * interpretiert, und um sie unverändert an grep weiterzuleiten.

Warum verliert der reguläre Ausdruck dann nicht '^-[0-9]'seine Bedeutung wie in einfachen Anführungszeichen? Normalerweise verliert alles innerhalb einfacher Anführungszeichen seine Bedeutung.

Ich danke Ihnen für Ihre Hilfe.

Antwort1

Andere haben Ihre spezifische Frage bereits beantwortet, aber ich möchte hinzufügen,

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

Ist aus mehreren Gründen eine falsche Methode zum Überprüfen, ob eine Zeichenfolge mit einem regulären Ausdruck übereinstimmt:

  1. Sie können nicht echofür beliebige Daten verwenden
  2. Das Lassen einer Parametererweiterung ohne Anführungszeichen wie $1oben entspricht dem Split+Glob-Operator.
  3. grepgleicht den regulären Ausdruck nicht mit der gesamten Eingabe ab, sondern mit jeder Zeile der Eingabe. Daher würde es foo\n-0\nbarbeispielsweise true zurückgeben.
  4. Ein regulärer Ausdruck kann mit der Länge Null übereinstimmen, daher ist es im Allgemeinen falsch, zu prüfen, ob grepeine Ausgabe erzeugt (beachten Sie, dass die Befehlsersetzung nachfolgende Zeilenumbruchzeichen entfernt). Es ist besser, grep -qden Beendigungsstatus von zu verwenden und sich darauf zu verlassen grep, anstatt auf den von [, und außerdem die Befehlsersetzung zu vermeiden.
  5. Beachten Sie, dass dieser grepBefehl vereinfacht werden kann zugrep -xE '-[0-9]+'

bashund haben einen eigenen Operator für (erweiterte) Regexp ksh93- zshMatching. Um es portabel und zuverlässig in allen drei (und Bash-3.1) zu verwenden, lautet die Syntax:

re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
  echo matches
fi

yashund zshunterstützen Sie auch:

if [ "$1" '=~' '^-[0-9]+$' ]; then
  echo matches
fi

Der Standardbefehl zum Durchführen von (grundlegenden) Regex-Abgleich von Zeichenfolgen lautet expr:

if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
  echo matches
fi

Beachten Sie, dass ^(aber nicht $) implizit in ist expr. Wir verwenden dieses führende Leerzeichen auch, um Probleme mit Werten von zu vermeiden, $1die Operatoren sind expr.

Beachten Sie auch, dass, wenn der reguläre Ausdruck enthält \(...\), dies das Verhalten von beeinflusst expr.

Alles in allem ist es besser, awkstattdessen Folgendes zu verwenden, was eine weitere standardmäßige/portable Möglichkeit ist (beachten Sie, dass awkerweiterte reguläre Ausdrücke verwendet werden):

if STRING=$1 RE='^-[0-9]+$' awk '
  BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...

Oder verwenden Sie eine Funktion:

re_match() {
  STRING=$1 RE=$2 awk '
    BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}

if re_match "$1" '^-[0-9]+$'

In diesem Fall können Sie es auch mit einem Standardkonstrukt erreichen case:

case $1 in
  ("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
  (*) echo match;;
esac

Um zu verwenden grep, können Sie es mit der --nullOption verwenden (sofern unterstützt, da dies keine Standardoption ist), um es anzuweisen, mit durch NULs getrennten Datensätzen statt mit durch Zeilenumbrüche getrennten Datensätzen zu arbeiten. Da in den meisten Shells $1keine NULs enthalten können, sollte dies sicher sein:

 if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
   echo match
 fi

Antwort2

Einfache Anführungszeichen weisen die Shell an, die Umschließungszeichen so zu belassen, wie sie sind.ohne jede Interpretation. Der in Anführungszeichen gesetzte String wird unverändert an übergeben grep, ohne Anführungszeichen: Bei grepder Suche nach den Argumenten wird Folgendes angezeigt:

grep

Und

^-[0-9][0-9]*$

und handelt danach. (Lesen SieSo werden Programme ausgeführtwenn Sie neugierig auf die Argumentkonstruktion in Linux sind.)

bashund grepsind unterschiedlich. Die Art und Weise, wie dieser Befehl Anführungszeichen verwendet, stellt sicher, dass bashdie Zeichenfolge nicht verarbeitet wird, sondern grepdies tut.

Antwort3

Einfache Anführungszeichen verhindernGlotzen( bashPlatzhalter wie interpretieren lassen *) und Variablenerweiterung durch die Verwendung von $. Im Grunde sagen Sie, bash„nehmen Sie diese Zeichen wörtlich und übergeben Sie sie an grep“. Wenn grepsie angezeigt werden, ist es so aufgebaut, dass es reguläre Ausdrücke versteht, alsoDannDer reguläre Ausdruck wird darin interpretiert grep.

Kürzere Version: Durch das Setzen einfacher Anführungszeichen für Argumente können Sie der Verarbeitung durch Ihre Shell entgehen, bevor das Argument an den Befehl übergeben wird.

Antwort4

Es verliert seine Bedeutung. grepverwendet fast dieselben Regex-Muster wie Bash.

verwandte Informationen