各行に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つの代替は次のとおりです。
]
点や記号ではなく、間の[
すべての項目を削除します[
(実際には空白に置き換えます。これは最終出力の空白です)。- 最初のものより前のすべてを削除してください
[
。 - 最後のもの以降のすべてを削除してください
]
。 - 残りのコンテンツからタグ付けされた単語を抽出します。
答え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]++'