次のログファイルがあります。
Another thousand lines above this
I 10/03/15 12:04AM 42 [Important] 4th to last
I 10/03/15 04:31AM 42 (534642712) [1974,2106,258605080,0,0,32817,30711]
I 10/03/15 04:33AM 42 (2966927) [91,0,2966927,0,0,291,291]
I 10/03/15 04:52AM 42 (3026559) [93,0,3026559,0,0,314,314]
I 10/03/15 04:55AM 42 (3065494) [94,0,3065494,0,0,301,301]
I 10/03/15 05:04AM 42 [Important] 3rd to last
I 10/04/15 12:04AM 42 [Important] 2nd to last occurence
I 10/04/15 04:31AM 42 (7,30711]55
I 10/04/15 04:33AM 42 dfsadfs,0,0,291,291]
I 10/04/15 04:52AM 42 (30,0,314,314]
I 10/04/15 04:55AM 42 (30,301]
I 10/04/15 05:04AM 42 [Important] - last occurence
ファイル全体で一定に保たれる唯一のパターンは、[Important]
各発生間の行数を含む他のすべてが変更されることです。[Important]
ファイルの終わりを取得しようとしています。最後の項目を無視し、最後の項目で2番目の項目を見つけて、残りのファイルを別のファイルに抽出しようとします。
これが私が試したことですが、tacを使用すると、最後から2番目のオカレンスを選択することはできません。私は何をしていますか?
<logfile tac | sed '/Important/q' | tac > output_file
出力は次のようになります。
I 10/04/15 12:04AM 42 [Important] 2nd to last occurence
I 10/04/15 04:31AM 42 (7,30711]55
I 10/04/15 04:33AM 42 dfsadfs,0,0,291,291]
I 10/04/15 04:52AM 42 (30,0,314,314]
I 10/04/15 04:55AM 42 (30,301]
I 10/04/15 05:04AM 42 [Important] - last occurence
答え1
「重要」のあるすべての行を探し、最後の2行を選択し、行番号を取得して範囲を印刷します。
sed -n `grep -n Important log | tail -n 2 | cut -d : -f 1 | tr '\n' ',' | sed -e 's#,$#p#'` log
出力は予想通りです。
I 10/04/15 12:04AM 42 [Important] 2nd to last occurence
I 10/04/15 04:31AM 42 (7,30711]55
I 10/04/15 04:33AM 42 dfsadfs,0,0,291,291]
I 10/04/15 04:52AM 42 (30,0,314,314]
I 10/04/15 04:55AM 42 (30,301]
I 10/04/15 05:04AM 42 [Important] - last occurence
スクリプトとして:
#!/bin/bash
lines=`grep -n Important log | tail -n 2 | cut -d : -f 1`
range=`echo "${lines}" | tr '\n' ',' | sed -e 's#,$#p#'`
sed -n "${range}" log
答え2
$ awk '/Important/{pen=s; s=$0;next} s{s=s"\n"$0} END{print pen "\n" s}' logfile
I 10/04/15 12:04AM 42 [Important] 2nd to last occurence
I 10/04/15 04:31AM 42 (7,30711]55
I 10/04/15 04:33AM 42 dfsadfs,0,0,291,291]
I 10/04/15 04:52AM 42 (30,0,314,314]
I 10/04/15 04:55AM 42 (30,301]
I 10/04/15 05:04AM 42 [Important] - last occurence
どのように動作しますか?
awk は、入力ファイルのすべての行を暗黙的に繰り返します。各発生後、Important
この行を変数に保存しますs
。新しい行に達すると、Important
重要な行の以前のセットが変数に転送され、pen
その中に新しい行が保存され始めますs
。
pen
2番目(2番目)の部分がありますImportant
。 s
最後(最後)のImportant
部分があります。最後にpen
合計を印刷しますs
。
もっと詳しく:
/Important/{pen=s; s=$0;next}
行にが含まれている場合は、
Important
変数の内容をに移動して現在の行を保存s
します。その後、残りのコマンドをスキップして次の行に移動します。pen
s
s{s=s"\n"$0}
ここに来たら現在の行には
Important
。s
値に設定されている場合は、現在の行をその値に追加します。END{print pen "\n" s}
ファイルの終わりに達した後、
pen
合計を印刷しますs
。
答え3
ed
オプションの場合:
ed -s file <<EOF
1
?Important
?
;w output_file
Q
EOF
答え4
sedがファイル全体をバッファリングできる場合(GNUなどを使用している場合は可能です)
(最後の編集:ここで複数のBrainosを修正しました)
sed -En 'H;$!d
g;s/.*[\n](.*Important.*\n.*Important[^\n]*).*/\1/p
'
ファイルの最後まで各行をバッファリングH;$!d
(「保留」)します。\n
以下は、$!d
最後の行がバッファリングされた後にのみ実行されます。g
g
etsバッファ。
正規表現を理解するには、正規表現が一番左にあり、最も長いことを覚えておいてください。リード。*検索最後のゲーム次の内容。H
aは無条件\n
の前に追加されるため、.*\n
2つの「有効」の前にあるすべての行とその間に少なくとも1つの改行文字があり、その後には次の行の前にあるすべての項目が一致します。
重要な2行がなければ、何も印刷されません。
不要な線を見つけたら、徐々に捨てることは少なくとも美学的に良いです。
sed -En 'H
/Important/ {x; s/.*[\n](.*Important.*\n.*Important[^\n]*)/\1/; H}
$ {g; s/.*[\n](.*Important.*\n.*Important[^\n]*).*/\1/p }
'
/Important/
変更パターンと保持バッファーを一致させ、最後の目的のブロックのみを保持し、x
結果を保持バッファーに戻します。
強調表示し、改行ではなく末尾のクラスと視覚的に一致させるために括弧内に入れます[\n]
。もちろん、括弧なしで単一文字クラスを作成することも可能です。