Bash: Cara mendapatkan beberapa baris dari file dan menyimpan output ke file lain [ditutup]

Jan 17 2021

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

dawg Jan 17 2021 at 22:29

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 awkAnda 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
WilliamPursell Jan 17 2021 at 17:57
$ 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

awkadalah 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.

potong Jan 17 2021 at 18:07

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.

IdrissNeumann Jan 17 2021 at 18:15

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, sortdan uniqtidak 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.

Enlico Jan 17 2021 at 18:47

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
EdMorton Jan 17 2021 at 22:50

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.