web-dev-qa-db-ja.com

GNUまたはBSD Sedの正規表現の代替または演算子(foo | bar)

うまく動かないようです。 GNU sedのドキュメントでは、パイプをエスケープするように言われていますが、これは機能しません。また、エスケープなしでストレートパイプを使用することもできません。括弧を追加しても違いはありません。

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog
31
Gregg Leventhal

デフォルトではsedPOSIX基本正規表現 を使用し、 |代替演算子が含まれていません。 GNUおよびFreeBSDを含む)sedの多くのバージョンは、 拡張正規表現 への切り替えをサポートしています。含む|代替。方法はさまざまです: GNU sedは-r を使用しますが、 FreeBSDNetBSDOpenBSD 、および OS X sed-Eを使用します。他のバージョンでは、ほとんどサポートされていません。次を使用できます。

echo 'cat dog pear banana cat dog' | sed -E -e 's/cat|dog/Bear/g'

これらのBSDシステムで動作し、GNUではsed -rになります。


GNU sed-Eを完全に文書化されていませんが実際にサポートされているようです。そのため、上記に限定されたマルチプラットフォームスクリプトがある場合は、それが最良のオプションです。それが文書化されていないので、あなたはおそらく本当にそれに頼ることはできません。

コメントには、BSDバージョンがドキュメント化されていないエイリアスとして-rもサポートしていることが記載されています。 OS Xはまだ今日ではなく、私がアクセスできる古いNetBSDおよびOpenBSDマシンもできませんが、NetBSD 6.1はできます。私が普遍的に到達できる商用ユニスはありません。したがって、この時点で移植性に関する質問はかなり複雑になっていますが、簡単な答えは、必要に応じて _awk に切り替えることです。どこでもEREを使用します。

36
Michael Homer

これは、(a|b)は、拡張正規表現であり、基本正規表現ではありません。使用 -Eこれに対処するオプション。

echo 'cat
dog
pear
banana
cat
dog'|sed -E 's/cat|dog/Bear/g'

sed manページから:

 -E      Interpret regular expressions as extended (modern) regular
         expressions rather than basic regular expressions (BRE's).

ご了承ください -rは同じものの別のフラグですが、-Eはより移植性が高く、POSIX仕様の次期バージョンにも含まれる予定です。

9
Nidal

これを行うためのポータブルな方法-より効率的な方法-はアドレスを使用することです。あなたはこれを行うことができます:

printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b' -e '};cBear'

このように、行に文字列catが含まれておらず、文字列dogが含まれていない場合、スクリプトからsedbranches、現在の行を自動印刷し、次の行をプルして次のサイクルを開始します。したがって、次の命令は実行されません。この例では、changによって行全体が読み取られますBearが、何でも実行できます。

また、sedコマンドの!bに続くステートメントは、文字列dogまたはcatのいずれかを含む行でonly一致できるため、さらに実行できることにも注意してください。一致しない行に一致する危険性のないテスト。つまり、どちらか一方のみにルールを適用できるようになります。

しかし、それは次です。上記のコマンドの出力は次のとおりです。

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

逆参照付きのルックアップテーブルを移植可能に実装することもできます。

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'

この単純な例の場合、設定するのははるかに手間がかかりますが、長期的には、より柔軟なsedスクリプトを作成できます。

最初の行で、exchangeホールドスペースとパターンスペースを保持し、次にexchangeする前に、ホールドスペースに文字列<space>cat<space>dog<space>を挿入します。

それ以降、次のすべての行で、Getはパターンスペースに追加されたスペースを保持し、行の先頭から最後に追加した改行までのすべての文字が、スペースで囲まれた文字列と一致するかどうかを確認します。もしそうなら、ロット全体をBearで置き換えます。そうでない場合、パターンスペースで最初に出現する改行までPrintだけなので、害はありません。次に、すべてdeleteします。

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

そして、私が柔軟と言うとき、それはそれを意味します。ここでは、catBrownBearに置き換え、dogBlackBear

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ 1cat Brown 2dog Black /;x
};G;s/^\(.*\)\n.* [0-9]\1 \([^ ]*\) .*/\2Bear/;P;d'

###OUTPUT###
BrownBear
BlackBear
pear
banana
BrownBear
BlackBear

もちろん、ルックアップテーブルの内容を大幅に拡張できます。90年代に、彼がどのようにして粗い計算機を構築したかを説明したときに、この件について Greg Ubben's usenet emailsからアイデアを見つけました。単一のsed s///ステートメントから。

6
mikeserv

これはかなり古い質問ですが、誰かが試したい場合に備えて、sedファイルを使用してsedでこれを行うためのかなり簡単な方法があります。各オプションは別々の行にリストすることができ、sedはそれぞれを評価します。 orと論理的に同等です。たとえば、特定のコードを含む行を削除するには:

あなたは言うことができます:sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'

またはこれをsedファイルに入れます:

/^\/\*!40103.*\/;$/d
/^\/\*!40101.*\/;$/d
/^\/\*!40111.*\/;$/d
1
Mordechai

以下は、sedの実装固有のオプションを使用しない手法です(-E-rなど)。パターンを単一の正規表現cat|dogとして記述する代わりに、sedを2回実行するだけです。

echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat/Bear/g' | sed 's/dog/Bear/g'

これは明らかな回避策ですが、共有する価値があります。当然、2つ以上のパターン文字列に一般化されますが、sedの非常に長いチェーンは見栄えがよくありません。

私はsed -i(これはすべての実装で同じように機能します)を使用してファイルを変更します。ここでは、一時的な結果がそれぞれファイルに保存されるため、パターン文字列の長いリストを適切に組み込むことができます。

for pattern in cat dog owl; do
    sed -i "s/${pattern}/Bear/g" myfile
done
0
jmd_dk