Bash: Cara mendapatkan beberapa baris dari file dan menyimpan output ke file lain [ditutup]
Saya memiliki file log seperti ini
$ cat build.log
..........
[ 60% 60917/101076] AAPT2 compile ....
[ 60% 60918/101076] AAPT2 compile ....
[ 60% 60919/101076] AAPT2 compile ....
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
#### failed to build some targets (17:26 (mm:ss)) ####
Cara menghasilkan seperti log parsing baru sehingga output dari file log baru seperti ini:
$ cat parsed.log
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
#### failed to build some targets (17:26 (mm:ss)) ####
Seperti hanya mendapatkan kemajuan terakhir [ 60% 60920/101076]
sampai akhir file, menggunakan mungkin grep, sed, atau apapun. Terima kasih
Jawaban
Ini perl:
$ perl -0777 -lne 'print $1 if /(^\[[^[]*\z)/m' file
Atau pipa perl:
$ perl -E 'say reverse <>' file | perl -lpE 'if (/^\[/){ say; last}' | perl -E 'say reverse <>'
Untuk awk
Anda dapat melakukan:
$ awk 'BEGIN{RS="\\["}END{print "[" $0}' file
Tentu saja, Anda mungkin tahu bahwa jika kegagalan selalu 3 baris, yang paling sederhana adalah menggunakan tail
:
$ tail -n 3 file
Semua cetak:
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
$ cat build.log ........ [ 60% 60917/101076] AAPT2 compile .... [ 60% 60918/101076] AAPT2 compile .... [ 60% 60919/101076] AAPT2 compile .... [ 60% 60920/101076] AAPT2 compile .... ninja: build stopped: subcommand failed. 21:41:22 ninja failed with: exit status 1 $ awk '$2 != n[2]{print p} {p = $0; split(p,n,FS)} END{print p}' build.log
........
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
awk
adalah alat yang tepat untuk hal semacam ini. Di sini, kami memeriksa apakah bidang ke-2 cocok dengan bidang ke-2 dari baris sebelumnya dan mencetak jika ya. Kemudian simpan baris sebelumnya dan ulangi. Selalu cetak baris terakhir masukan.
Ini mungkin berhasil untuk Anda (GNU sed):
sed '/^\[/h;//!H;$!d;x' file
Jika sebuah garis mulai [
menyimpannya di ruang tunggu (menimpa apa pun yang sebelumnya ada di sana).
Atau, tambahkan baris saat ini ke ruang tunggu.
Hapus semua baris kecuali yang terakhir.
Di akhir file, tukar ke ruang tunggu dan cetak isinya.
Anda terkadang tidak beruntung jika ingin melakukan filter semacam ini tanpa harus mengubah urutan garis. Dan jika garis tidak ditulis di awal file Anda, atau di akhir: tac
, sort
dan uniq
tidak akan menjadi alat yang tepat.
Berikut solusinya menggunakan awk
:
$ awk 'function push(a,e) { a[length(a)+1] = e } BEGIN {split("", lines); to_replace="toreplace"; exists=0} {if ($0 ~ "^\\[ [0-9]+%"){ll=$0; if (exists <= 0) {exists++; push(lines,to_replace)}} else {push(lines, $0)}} END {for (e in lines){if (lines[e] == to_replace) {print ll} else {print lines[e]}}}' test.log
..........
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
#### failed to build some targets (17:26 (mm:ss)) ####
Versi yang dapat dibaca dan dijelaskan:
# a function to append an element to an array dynamically
function push(a,e) {
a[length(a)+1] = e
}
BEGIN {
split("", lines); # initializing an array
to_replace="toreplace"; # you can change the replace key if you want
exists=0
}
{
if ($0 ~ "^\\[ [0-9]+%"){ # matching all percentages/progression lines, regardless of their values ll=$0;
if (exists <= 0) {
exists++;
push(lines, to_replace)
}
} else {
push(lines, $0)
}
}
END {
for (e in lines) {
if (lines[e] == to_replace) {
print ll
} else {
print lines[e]
}
}
}
Perbedaan dengan solusi William Pursel adalah ketika persentase Anda meningkat. Mari kita lihat perbedaan perilaku dalam kasus ini:
$ cat test.log
..........
[ 60% 60917/101076] AAPT2 compile ....
[ 60% 60918/101076] AAPT2 compile ....
[ 60% 60919/101076] AAPT2 compile ....
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
#### failed to build some targets (17:26 (mm:ss)) ####
$ awk 'function push(a,e) { a[length(a)+1] = e } BEGIN {split("", lines); to_replace="toreplace"; exists=0} {if ($0 ~ "^\\[ [0-9]+%"){ll=$0; if (exists <= 0) {exists++; push(lines,to_replace)}} else {push(lines, $0)}} END {for (e in lines){if (lines[e] == to_replace) {print ll} else {print lines[e]}}}' test.log
..........
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
#### failed to build some targets (17:26 (mm:ss)) ####
$ awk '$2 != n[2]{print p} {p = $0; split(p,n,FS)} END{print p}' test.log
..........
[ 60% 60919/101076] AAPT2 compile ....
[ 61% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
#### failed to build some targets (17:26 (mm:ss)) ####
Jadi Anda mungkin ingin memilih apakah Anda hanya ingin mempertahankan garis perkembangan terakhir meskipun persentasenya tidak sama atau jika Anda hanya ingin memfilter garis yang memiliki persentase yang sama beberapa kali.
Jika dijamin bahwa baris pertama yang ingin Anda ouput itu adalah baris terakhir yang dimulai [
, maka Anda dapat melakukan ini, yang pada dasarnya menggantikan semuanya dari awal file hingga yang terakhir yang [
didahului oleh pemutusan baris dengan satu [
:
sed -z 's/.*\n\[/[/' file
Dengan asumsi ...
garis di awal masukan sampel Anda mewakili lebih banyak [...] ...
garis terdepan :
$ awk '/^\[/{p=$0 ORS; next} {print p $0; p=""}' build.log
[ 60% 60920/101076] AAPT2 compile ....
ninja: build stopped: subcommand failed.
21:41:22 ninja failed with: exit status 1
#### failed to build some targets (17:26 (mm:ss)) ####
Jika asumsi tersebut salah, edit pertanyaan Anda untuk menunjukkan contoh yang minimal, lengkap , dan dapat diverifikasi - satu dengan hanya nilai perwakilan, bukan ...
s.