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


28

私はそれを機能させることができないようです。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

回答:


33

デフォルトでsedは、代替演算子を含まないPOSIX Basic Regular Expressionsを使用します|sedGNUやFreeBSDを含むの多くのバージョンは、代替を含む拡張正規表現への切り替えをサポートしています|。その方法は異なります。GNUsedの使用-rFreeBSDNetBSDOpenBSD、およびOS Xのsedの使用-E。他のバージョンではほとんどサポートされていません。次を使用できます。

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

そして、それらのBSDシステムで、そしてsed -rGNU で動作します。


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

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


あなたが言及した3つのBSDはすべて、GNU sedとの互換性の-r同義語としてこのオプションをサポートしています-E。OpenBSDおよびOS X sed -Eは、エスケープされたパイプを、代替演算子ではなくリテラルパイプとして解釈します。ここでは作業リンクの NetBSDのmanページには、と、ここで一つだ 10歳ではありませんOpenBSDのため。
ダミアン14



9

これ(a|b)は、基本正規表現ではなく拡張正規表現であるために発生します。-Eこれに対処するにはオプションを使用してください。

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

sedmanページから:

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

これ-rは同じことに対する別のフラグですが、-Eより移植性があり、POSIX仕様の次のバージョンにも含まれることに注意してください。


6

これを行うための移植可能な方法-より効率的な方法-はアドレスを使用する方法です。あなたはこれを行うことができます:

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

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

また!b、そのsedコマンドの次のステートメントは、文字列または- を含む行でのみ一致するので、注意してください-一致しない行と一致する危険なしに、さらにテストを実行できます-これは、ルールを適用できることを意味しますどちらか一方だけにも。dogcat

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

###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かかりますが、長期的にははるかに柔軟なスクリプトを作成できます。

最初の行では、xホールドスペースとパターンスペースを変更し、文字列<space>cat <space>dog<space>をホールドスペースに挿入しxてから元に戻します。

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

###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の usenetメールからアイデアを選びましたsed s///


1
ふう、+ 1。あなたは私が言わなければならない箱から出して考えるための傾向を持っている
iruvar

@ 1_CR-私の最後の編集-私のアイデアではなく-を参照してください。しかし、私はそれが当然であるところで信用を与えるのが好きです。
mikeserv 14

1

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

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

またはこれをsedファイルに入れてください:

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

0

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

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

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

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

for pattern in cat dog owl; do
    sed -i "s/${pattern}/Bear/g" myfile
done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.