sed:1行で複数回発生するパターンからテキストを抽出します。

sed:1行で複数回発生するパターンからテキストを抽出します。

各行に1〜n回表示される文字列部分を抽出する必要があります。

たとえば、これは私に必要なものを反映しています。

This [dbo].[something] is a text containing [dbo].[something_else], then okay?
And then, [dbo].[something] may appear just once.
But why, nothing prevents [dbo].[something] from appearing twice as [dbo].[something] here.
And then can be three times, as [dbo].[something] is [dbo].[anything] but [dbo].[elsewhere] here.
[dbo].[otherthing] depicts another scenario with just one and pattern heading line
Or, also [dbo].[ultra] with an arbitrary amount of [dbo].[references] but ending with [dbo].[pattern]

\[dbo\]\.\[[^]]+\]たとえば、上記のテキストでは、次のような結果が必要です。

something something_else
something
something something
something anything elsewhere
otherthing
ultra references pattern

その後、すべてをインライン化したり、bash配列に追加したり、重複した項目をフィルタリングしたりできます。これは問題ではありません。 1回のスキャンでこのフィルタを実行する方法を特定するのに問題があります。

ここで私が得たのは、最後の一致だけを抽出することです(パターン一致に対するsedの「欲張りな」アプローチに慣れているのであれば、これがなぜそうなのかは明らかです)。

cat dborefs.txt | sed -E "s/(.*\[dbo\]\.\[([^]]+)\].*)*/\2/g"
something_else
something
something
elsewhere
otherthing
pattern

パターンを抽出して置き換えることで、一致しなくなり、一致しなくなるまで再抽出できますが、すべてのbashオーバーヘッドを考慮すると、あまりにも多くの問題のように聞こえます。すべてを一つに抽出できればいいでしょう。呼ぶsed。これが可能でなければならないと思いますが、どうすればよいかわかりません。私はこれが他の人に役立つと思ったので、コミュニティでこの質問をここで共有することが有益であると感じました。

答え1

改行で区切られたトークン文字列のリストを取得するには、次のようにします。

$ grep -o '\[dbo\]\.\[[^]]*\]' file | cut -d . -f 2 | tr -d '[]'
something
something_else
something
something
something
something
anything
elsewhere
otherthing
ultra
references
pattern

最初はgrepビットを生成し[dbo].[word]、その合計を削除cutします。[word]tr[]

トークン文字列を発生する行ごとにグループ化するには、次のようにします。

$ sed -e 's/\][^.[]*\[/] [/g' -e 's/^[^[]*//' -e 's/[^]]*$//' -e 's/\[dbo\]\.\[\([^]]*\)\]/\1/g' file
something something_else
something
something something
something anything elsewhere
otherthing
ultra references pattern

ここで使用される4つの代替は次のとおりです。

  1. ]点や記号ではなく、間の[すべての項目を削除します[(実際には空白に置き換えます。これは最終出力の空白です)。
  2. 最初のものより前のすべてを削除してください[
  3. 最後のもの以降のすべてを削除してください]
  4. 残りのコンテンツからタグ付けされた単語を抽出します。

答え2

現在、sedを繰り返し呼び出すよりも良い方法は、ファイルに表示されないプレースホルダ「リンク」に置き換えることです。

cat dborefs.txt | sed -E "
 s/\[dbo\]\.\[([^]]+)\]/_-\1-_/g;
 s/(^|-_)([^_]+|_[^-])*(\$|_-)/ /g;
 s/(^ +| +\$)//g"

言い換えれば:

  • まず、すべてを[dbo].[<extract>]取得します_-<extract>-_
  • 次に、最後のテキストの前_-、間、および後ろ-_のすべてのテキストを単一の空白文字に置き換えます。_--_
  • 次に、各行の先頭と末尾の空白文字をクリーンアップします。

これにより、目的の結果が得られます。これをすべて配列にリンクしてから、sort一意の項目をフィルタリングできます。しかし、私はまだコマンドをリンクしないより良い方法があるべきだと思いますsed

答え3

一致を一意にするためにハッシュ(連想配列)を使用すると、Perlでこれを簡単に実行できます。

$ perl -nE 'while ($_ =~ /\[dbo\]\.\[(.*?)\]/g) {$h{$1}++} }{ for $k (keys %h) {say $k}' dborefs.txt 
otherthing
anything
elsewhere
something
pattern
something_else
ultra
references

この関数を繰り返し適用すると、GNU Awkでも同様のアプローチが可能ですmatch

$ gawk '{
    while (match($0,/\[dbo\]\.\[([^]]+)\]/,a)) {h[a[1]]++; $0 = substr($0,RSTART+RLENGTH)}
  } 
  END{
    for (k in h) print k
  }' dborefs.txt 
references
elsewhere
something
something_else
pattern
otherthing
anything
ultra

キャプチャグループ配列を提供しない機能を持つ他のAwk実装では、match一致を切り捨てる必要があります。

while (match($0,/\[dbo\]\.\[([^]]+)\]/)) {h[substr($0,RSTART+7,RLENGTH-8)]++; $0 = substr($0,RSTART+RLENGTH)}

答え4

今回は、複数のユーティリティを使用する別の方法があります。パイプラインのsed部分はパターンを抽出し、awk部分は最初の発生順序を維持しながらパターンを一意に指定します。

sed -Ee '
  /\n/{P;D;}
  s/\[dbo]\.\[([^]]+)]/\n\1\n/;D
' dborefs.txt | awk '!a[$0]++'

関連情報