この出力があります。
[root@linux ~]# cat /tmp/file.txt
virt-top time 11:25:14 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
ID S RDRQ WRRQ RXBY TXBY %CPU %MEM TIME NAME
1 R 0 0 0 0 0.0 0.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.0 0.0 95:44:07 instance-00000372
virt-top time 11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
ID S RDRQ WRRQ RXBY TXBY %CPU %MEM TIME NAME
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
あなたはそれが2つのブロックを持っているのを見ることができ、私は最後のブロックを抽出したい(あなたが最初のブロックを見るならそれは私が気にしないすべてのCPUゼロを持っている) -*)それ以外の場合は、「tail -n 2」を使用できます
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
私はsed/awk/grepとすべての可能な方法を試しましたが、希望する結果に近づきませんでした。
これは少しばかげた感じですが、
$ tac file.txt |sed -e '/^virt-top/q' |tac
virt-top time 11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
ID S RDRQ WRRQ RXBY TXBY %CPU %MEM TIME NAME
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
GNU tac
はファイルを逆にします(多くの非GNUシステムには代わりにtail -r
があります)、sed
はvirt-top
で始まる最初の行まで行を選択します。 sed 1,2d
またはtail -n +3
を追加してヘッダーを削除できます。
またはawkで:
$ awk '/^virt-top/ { a = "" } { a = a $0 ORS } END {printf "%s", a}' file.txt
virt-top time 11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
ID S RDRQ WRRQ RXBY TXBY %CPU %MEM TIME NAME
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
変数へのすべての行を収集し、virt-top
で始まる行でその変数をクリアするだけです。
ファイルが非常に大きい場合、tac
ソリューションがファイルを読み取る間、ファイルの末尾のみを読み取る必要があるため、sed
+ awk
ソリューションはより高速になるはずです。上からファイル全体。
ed
を使用すると、通常の?pattern?
(現在の位置の上から検索)の代わりに/pattern/
を使用してregex-search pwardを使用できます。だから例えば:
$ printf '%s\n' '?ID?+1,$p' q | ed -s file.txt
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
入力に固定数のブロックがある場合は、次のようなこともできます。
awk '/^virt-top/ && ++n == 2, 0' <your-file
2からラインを出力するにはndvirt-top
の出現からファイルの終わりまで(0はfalseを意味し、その終わりを意味しますfirst、lastの範囲は決して見つかりました)。
文字列virt-top
で始まる行から最後のレコードをed
を使用して最後まで取得します(数メガバイトではなく、表示されているものと同等のサイズのファイルを処理するのに適しています)。
$ printf '%s\n' '?^virt-top?,$p' | ed -s file
virt-top time 11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
ID S RDRQ WRRQ RXBY TXBY %CPU %MEM TIME NAME
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
または、サブストリングinstance
を含む最後のvirt-top
行の直後の行:
$ printf '%s\n' '?^virt-top?,$g/instance/p' | ed -s file
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
その最後のed
コマンド?^virt-top?,$g/instance/p
は、最初にvirt-top
で始まる最後の行からの範囲を指定します(最後にed
が最後のバッファーの行と?re?
を逆方向に検索して)バッファーの最後($
)に移動し、コマンドg/instance/p
をこれらの行に適用します。 g/re/p
コマンドは、指定された正規表現に一致する範囲内のすべての行を出力します(ところでgrep
はその名前を取得した場所です)。
awk
の使用:
$ awk '/^virt-top/ { lines = "" } /instance/ { lines = (lines == "" ? $0 : lines ORS $0) } END { print lines }' file
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
これにより、部分文字列lines
を含む行がある場合は、入力行がinstance
に保存されます。これらの行は最後に印刷されます。 virt-top
で始まる行が見つかると、保存された行は破棄されます。
sed
とほぼ同じで、ホールドスペースを使用してlines
コードのawk
変数と同等の機能を果たします。
$ sed -n '/^virt-top.*/{ s///; x; d; }; /instance/H; ${ x; s/\n//; p; }' file
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
これを処理する別の方法を次に示します。
$ sed -e '
/\n/q
/virt-top/{h;d;}
H;$!d;g
s/\n//;D
' file.txt
結果
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372