web-dev-qa-db-ja.com

正規表現を使ってbashで検索して置換する

私はこの例を見ました:

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

これは次の構文に従います:${variable//pattern/replacement}

残念ながら、patternフィールドは完全な正規表現構文をサポートしていないようです(たとえば、.または\sを使用した場合、リテラル文字と一致させようとします)。

正規表現を使って文字列を検索/置換するにはどうすればいいですか?

129
Lanaru

sed を使用してください。

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

後続の-eは順番に処理されることに注意してください。また、式のgフラグは、入力内のすべての出現箇所と一致します。

この方法で好きなツールを選ぶこともできます。例:Perl、awk、

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

これにより、よりクリエイティブな一致を行うことができます。たとえば、上記のスニップでは、最初の式に一致がない限り、数値置換は使用されません(遅延and評価のため)。そしてもちろん、あなたはあなたの入札をするためにPerlの全言語サポートを持っています...

132
jheddings

これは実際にはできます純粋なbashで行うことができます。

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

...歩留まり...

howareyoudoingtodday
115
Charles Duffy

これらの例は、bashでも機能します。sedを使用する必要はありません。

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

文字クラスのかっこ式も使用できます。

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

出力

XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX

質問を正しく理解した場合、@Lanaruが知りたかったのは、 "full"またはPCRE拡張\s\S\w\W\d\Dなどが、php Ruby pythonなどでサポートされているように機能しない理由です。これらの拡張は、Perl互換の正規表現(PCRE)によるものです。他の形式のシェルベースの正規表現とは互換性がない可能性があります。

これらはうまくいきません。

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


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

すべてのリテラル "d"文字を削除して出力

ho02123ware38384you44334o3434ingto38384ay

しかし、以下は期待通りに動作します。

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

出力

howareyoudoingtodday

もう少し明確にしてほしいのですが、まだ混乱していないのであれば、REG_ENHANCEDフラグが有効になっているMac OS Xで試してみませんか。

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

ほとんどの種類の* nixでは、次のような出力しか表示されません。

d
d
d

nジョイ!

79
nickl-

繰り返し呼び出しを行い、パフォーマンスに関心がある場合、このテストではBASHメソッドがsedや他の外部プロセスへのフォークよりも15倍高速であることがわかります。

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]
10
Josiah DeWitt

パターンとして[[:digit:]](二重括弧に注意)を使用します。

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

ただ答えを要約したかっただけです(特に@ nickl- https://stackoverflow.com/a/22261334/2916086 )。

4
yegeniy