it-swarm.com.de

Suchen und Ersetzen in Bash mit regulären Ausdrücken

Ich habe folgendes Beispiel gesehen:

hello=ho02123ware38384you443d34o3434ingtod38384day
echo ${hello//[0-9]/}

Was folgt dieser Syntax: ${variable//pattern/replacement}

Leider scheint das Feld pattern nicht die vollständige Regex-Syntax zu unterstützen (wenn ich zum Beispiel . Oder \s Verwende, versucht es, die Literalzeichen abzugleichen).

Wie kann ich eine Zeichenfolge mit vollständiger Regex-Syntax suchen/ersetzen?

133
Lanaru

Verwenden Sie sed :

MYVAR=ho02123ware38384you443d34o3434ingtod38384day
echo "$MYVAR" | sed -e 's/[a-zA-Z]/X/g' -e 's/[0-9]/N/g'
# prints XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX

Beachten Sie, dass die folgenden -e 's werden in Reihenfolge verarbeitet. Außerdem stimmt das g -Flag für den Ausdruck mit allen Vorkommen in der Eingabe überein.

Mit dieser Methode können Sie auch Ihr Lieblingswerkzeug auswählen, d. H. Perl, awk, z.

echo "$MYVAR" | Perl -pe 's/[a-zA-Z]/X/g and s/[0-9]/N/g'

Auf diese Weise können Sie möglicherweise mehr kreative Übereinstimmungen erstellen. Im obigen Ausschnitt wird beispielsweise die numerische Ersetzung nur verwendet, wenn der erste Ausdruck übereinstimmt (aufgrund einer verzögerten and Auswertung). Und natürlich haben Sie die volle Sprachunterstützung von Perl, um Ihre Gebote abzugeben ...

141
jheddings

Dies kann tatsächlich in reiner Bash erfolgen:

hello=ho02123ware38384you443d34o3434ingtod38384day
re='(.*)[0-9]+(.*)'
while [[ $hello =~ $re ]]; do
  hello=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
done
echo "$hello"

... ergibt ...

howareyoudoingtodday
117
Charles Duffy

Diese Beispiele funktionieren auch in bash, ohne dass sed verwendet werden muss:

#!/bin/bash
MYVAR=ho02123ware38384you443d34o3434ingtod38384day
MYVAR=${MYVAR//[a-zA-Z]/X} 
echo ${MYVAR//[0-9]/N}

sie können auch die Klammerausdrücke der Zeichenklasse verwenden

#!/bin/bash
MYVAR=ho02123ware38384you443d34o3434ingtod38384day
MYVAR=${MYVAR//[[:alpha:]]/X} 
echo ${MYVAR//[[:digit:]]/N}

ausgabe

XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX

Was @ Lanaru allerdings wissen wollte, wenn ich die Frage richtig verstehe, ist warum die "full" - oder PCRE-Erweiterung \s\S\w\W\d\D etc funktionieren nicht wie in php Ruby python usw.) unterstützt. Diese Erweiterungen stammen von Perl-kompatiblen regulären Ausdrücken (PCRE) und sind möglicherweise nicht kompatibel mit anderen Formen von Shell-basierten regulären Ausdrücken.

Diese funktionieren nicht:

#!/bin/bash
hello=ho02123ware38384you443d34o3434ingtod38384day
echo ${hello//\d/}


#!/bin/bash
hello=ho02123ware38384you443d34o3434ingtod38384day
echo $hello | sed 's/\d//g'

ausgabe mit allen Literalen "d" Zeichen entfernt

ho02123ware38384you44334o3434ingto38384ay

aber das folgende funktioniert wie erwartet

#!/bin/bash
hello=ho02123ware38384you443d34o3434ingtod38384day
echo $hello | Perl -pe 's/\d//g'

ausgabe

howareyoudoingtodday

Hoffe, das klärt die Dinge ein bisschen mehr, aber wenn Sie noch nicht verwirrt sind, warum versuchen Sie es nicht unter Mac OS X, bei dem das Flag REG_ENHANCED aktiviert ist:

#!/bin/bash
MYVAR=ho02123ware38384you443d34o3434ingtod38384day;
echo $MYVAR | grep -o -E '\d'

Auf den meisten Versionen von * nix wird nur die folgende Ausgabe angezeigt:

d
d
d

nJoy!

80
nickl-

Wenn Sie wiederholte Anrufe tätigen und sich mit der Leistung befassen, zeigt dieser Test, dass die BASH-Methode ~ 15x schneller ist als das Verzweigen auf sed und wahrscheinlich jeder andere externe Prozess.

hello=123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X

P1=$(date +%s)

for i in {1..10000}
do
   echo $hello | sed s/X//g > /dev/null
done

P2=$(date +%s)
echo $[$P2-$P1]

for i in {1..10000}
do
   echo ${hello//X/} > /dev/null
done

P3=$(date +%s)
echo $[$P3-$P2]
12
Josiah DeWitt

Verwenden [[:digit:]] (doppelte Klammern beachten) als Muster:

$ hello=ho02123ware38384you443d34o3434ingtod38384day
$ echo ${hello//[[:digit:]]/}
howareyoudoingtodday

Ich wollte nur die Antworten zusammenfassen (insbesondere @ nickl -'s https://stackoverflow.com/a/22261334/2916086 ).

4
yegeniy