sedで複数の感嘆符を使用する意味は何ですか?


12

POSIX sedのドキュメントによると:

関数の前に1つ以上の「!」を付けることができます。この場合、アドレスがパターンスペースを選択しない場合に機能が適用されます。ゼロ個以上の<空白>文字は、最初の '!'の前に受け入れられます。キャラクター。<空白>文字が「!」の後に続くことができるかどうかは指定されていません。文字、および適合アプリケーションは、「!」<空白>文字を含む文字。

したがって、POSIX sedを使用すると、次のことができます。

sed -e '/pattern/!d' file

書くのと同じです:

sed -e '/pattern/!!d' file

そして!!!dn感嘆符はまだ大丈夫です(家宝ツールチェストの 3つのsedバージョンでテスト済み)。1つの感嘆符の代わりに複数の感嘆符の間に利点はありません。

なぜ仕様がその構文を許可し、実際のアプリケーションでどのように役立つのですか?


この場合、GNU sedは準拠していないようで、複数の感嘆符を使用すると文句を言います。

$ sed -e '/pattern/!!d' file
sed: -e expression #1, char 11: multiple `!'s

2
FWIW:OpenBSD !では、トグルとして機能/pattern/!!/pattern/、と同じであり、と/pattern/!!!同じ/pattern/!です。FreeBSDでは、複数!は単一のものと同じです。
lcd047

2
仕様の多くのもののポイントはsedスクリプトを生成できるということです。POSIXを考えると、sedスクリプトの記述をスクリプト化することは現実的に単純な問題であるはずsedです。そのため、何らかの!アクションにふさわしくないアドレスをマークする何らかのトリガーが発生した場合、同じアクションに対して複数回トリガーしても同じ結果が得られる可能性があります。
mikeserv

@cuonglmいいえ、FreeBSDのみです。GNU、OpenBSD、およびNetBSD sedはそうではありません。
lcd047

@ lcd047:ええ、もちろん。私の悪い英語でごめんなさい。つまり、準拠していません。それを知ってうれしいです。しかし、私の質問の主なポイントは、その構文がPOSIX sedを使用して実際にどのように役立つということです。
クオンルム

1
FWIW:この修正はOpenBSD-currentでコミットされています。
-lcd047

回答:


5

sedのAPIはプリミティブです-これは仕様によるものです。少なくとも、それは残っいます設計上原始的ます-私が言うことができない初期に原始的に設計されたかどうか。ほとんどの場合、sed実行時に別のsedスクリプトを出力するスクリプトを書くことは、本当に簡単なことです。および/またはsedなどのマクロプリプロセッサによって、この方法で非常に頻繁に適用されます。m4make

(以下は非常に仮説的なユースケースです。それはソリューションに合うように設計された問題です。それがあなたにとってストレッチのように思えるのであれば、それはおそらくそれが理由です。


次の入力ファイルを検討してください。

cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower

上記の入力ファイルの適切な各単語の末尾に-casesed追加するスクリプトを記述したい場合は、適切なコンテキストの、できるだけ効率的に実行したい(たとえば、コンパイル操作中の目標であるように)/regexp /を可能な限り適用しないようにする必要があります。

できることの1つは、システム上でファイルを事前に編集し、sedコンパイル中にまったく呼び出しないことです。しかし、ファイル内のこれらの単語のいずれかをローカル設定および/またはコンパイル時オプションに基づいて含める必要がある場合、または含めない場合、そうすることは望ましい代替手段ではない可能性があります。

私たちがするかもしれないもう一つは、ファイルを処理することです 今、正規表現に対して。sed行番号に従って編集を適用できるスクリプトを作成し、コンパイルに含めることができます。これは通常、長期的にははるかに効率的なルートです。

例えば:

n=$(printf '\\\n\t')
grep -En 'camel|upper|lower' <infile |
sed "   1i${n%?}#!/usr/heirloom/bin/posix2001/sed -nf
        s/[^:]*/:&$n&!n;&!b&$n&/;s/://2;\$a${n%?}q"'
        s/ *cat/!/g;s/ *dog/!/g
        s| *\([cul][^ ]*\).*|s/.*/\1-case/p|'

...出力をaの形式で書き込みます sedスクリプト次のようになります...

#!/usr/heirloom/bin/posix2001/sed -nf
:1
    1!n;1!b1
    1s/.*/camel-case/p
:2
    2!n;2!b2
    2!!s/.*/camel-case/p
:5
    5!n;5!b5
    5s/.*/upper-case/p
:6
    6!n;6!b6
    6s/.*/lower-case/p
q

その出力が私のマシン上の実行可能なテキストファイルに保存され、の./bang.sedよう./bang.sed ./infileに実行されると、出力は次のようになります。

camel-case
upper-case
lower-case

今、あなたは私に尋ねるかもしれません... なぜ私はそれをしたいのですか?なぜアンカーgrepの一致だけではないのですか?とにかくラクダケースを使用するのは誰ですか?そして、それぞれの質問に答えることしかできませんでした。私はしませんので。この質問を読む前に、私は個人的にマルチに気づいていませんでした仕様の解析要件-私はそれがかなりきちんとしたキャッチだと思います。

マルチ!事はなかったすぐにかかわらず、私には意味をなさない-の多くのsed仕様は、単に解析され、単純に向けている生成され sedたスクリプト。あなたはおそらく、そのコンテキストではるかに意味\n[wr:bt{]なすために必要なewline区切り文字を見つけるでしょう、そしてその考えを覚えておけば、仕様の他のいくつかの側面をよりよく理解するかもしれません- :アドレスを受け入れない、qに拒否します1)以上を受け入れます

例では、私は、特定の形式に書き出すの上にsedできるだけでスクリプト今までに一度読むことを。それをよく見るsedと、編集ファイルを読み込むと、コマンドブロックから次のコマンドブロックに進むことに気付くかもしれません。

私はそのマルチを検討します!アドレスは他のいくつかのコンテキストよりもそのコンテキストでより有用かもしれませんが、正直なところ、私はそれを非常に有効に使用したかもしれない単一のケースを考えることはできません-そして私sedはたくさん。また、GNU / BSD sedの両方が指定どおりに処理できないことは注目に値すると思います-これはおそらく要求の多い仕様の一部ではないため、実装を見落とすと、バグ@ボックスが非常に深刻になることを疑います結果としてひどく。

それは言った、指定されたとして、これを処理するために、障害があるコンプライアンスたふりを任意の実装のバグ、と私は呼ば-のためにされてここでは関係のdevのボックスに電子メールを撮影し、そうでない場合、私はそうするつもりだと思うので。


1
現在、OpenBSD-currentで修正されています。
lcd047

1
複数!次の仕様で削除される予定です、ここで何が起こっているのでしょう!
クオンルム

@cuonglm-遅すぎると思う。多分私は思ったよりもマークに近かった。
mikeserv

@cuonglm-まあ、わかりましたが、それは何を意味します... Marked as Markedはどういう意味ですか?
mikeserv

1
@mikeserv:答えは私の不思議を説明し、sed APIの別の見方を与えてくれました。理にかなっています!
クオンルム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.