web-dev-qa-db-ja.com

2つの文字列間で最後に出現する文字列のログファイルをGrepします。

ログファイルtrace.logがあります。その中で、文字列<tag>および</tag>に含まれるコンテンツをgrepする必要があります。この文字列のペアには複数のセットがあり、最後のセットの間(つまり、ログファイルのtailから)のコンテンツを返すだけです。

追加クレジット:コンテンツに「testString」が含まれている場合にのみ、2つの文字列に含まれるコンテンツを返す方法はありますか?

見てくれてありがとう。

編集:検索パラメーターは、異なる行に含まれており、約100行のコンテンツで区切られています。内容は私が求めているものです...

24
rs79

tacを使用してファイルを逆方向​​に印刷し、_grep -m1_を使用して1つの結果のみを印刷します。後読みと先読みは、_<tag>_と_</tag>_の間のテキストをチェックします。

_tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'
_

テスト

このファイルを考える

_$ cat a
<tag> and </tag>
aaa <tag> and <b> other things </tag>
adsaad <tag>and  last one</tag>

$ tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'
and  last one
_

更新

編集:検索パラメーターは、異なる行に含まれており、約100行のコンテンツで区切られています。内容は私が求めているものです...

それからもう少しトリッキーです:

_tac file | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]};
                /<tag>/   {p=0; split($0, a, "<tag>");  $0=a[2]; print; exit};
                p' | tac
_

ファイルを反転させ、pフラグを使用して_<tag>_がまだ出現しているかどうかを確認するという考え方です。 _</tag>_が表示されたときに印刷を開始し、_<tag>_が来たときに終了します(逆方向に読んでいるため)。

  • split($0, a, "</tag>"); $0=a[1];は、_</tag>_の前のデータを取得します
  • split($0, a, "<tag>" ); $0=a[2];は_<tag>_の後にデータを取得します

テスト

次のようなファイルaを指定します。

_<tag> and </tag>
aaa <tag> and <b> other thing
come here
and here </tag>

some text<tag>tag is starting here
blabla
and ends here</tag>
_

出力は次のようになります。

_$ tac a | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]}; /<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit}; p' | tac
tag is starting here
blabla
and ends here
_
33
fedorqui

私のように、システム管理者がボールをプレーできないため、tacにアクセスできません。

grep pattern file | tail -1
22
SlackGadget

Grep以外の別の解決策はsedです:

tac file | sed -n '0,/<tag>\(.*\)<\/tag>/s//\1/p'

tac fileは逆順(catの逆順)でファイルを出力し、その後sedは入力行0から<tag>.*<\tag>の最初の出現まで進みます。 <tag>.*<\tag><tag>の中にあった部分のみで置き換えます。 pフラグは、-nによって抑制された出力を出力します。

編集:<tag></tag>が異なる行にある場合、これは機能しません。そのためにsedを使用できます:

tac file | sed -n '/<\/tag>/,$p; /<tag>/q' | sed 's/.*<tag>//; s/<\/tag>.*//' | tac

再びtacを使用してファイルを逆方向​​に読み取り、最初のsedコマンドはの最初の出現から読み取り、を検出すると終了します。間の行のみが印刷されます。次に、それを別のsedプロセスに渡して、 'sを取り除き、最後にtacで行を逆にします。

1
pfnuesel
Perl -e '$/=undef; $f=<>; Push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1]' ex.txt

追加クレジット:コンテンツに「testString」が含まれている場合にのみ、2つの文字列に含まれるコンテンツを返す方法はありますか?

Perl -e '$/=undef; $f=<>; Push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1] if ($a[-1]~=/teststring/);' ex.txt
0
Vorsprung

複数の行を処理する小さな未テスト awk:

awk '
    BEGIN    {retain="false"}
    /<\tag>/ {retain = retain + $0; keep="false"; next}
    /<tag>/  {keep = "true"; retain = $0; next}
    keep == "true" {retain = retain + $0}
    END {print retain}
' filename

ファイルの読み取りを開始します。を押すと、行を保持し始めます。を押すと停止します。別のをヒットした場合、保持された文字列をクリアして、やり直します。すべての文字列が必要な場合は、それぞれで印刷します

0
mpez0