GNU/Linux >> Belajar Linux >  >> Linux

Cetak baris sebelumnya jika kondisi terpenuhi

Opsi lain:balikkan file dan cetak berikutnya baris jika kondisi cocok:

tac file | awk '$1 == "BB" && $2 > 1 {getline; print}' | tac

Tentang keumuman

Saya pikir perlu disebutkan bahwa solusi paling umum untuk kelas masalah ini melibatkan dua lintasan:

  • pass pertama untuk menambahkan nomor baris desimal ($REC) ke depan setiap baris, secara efektif mengelompokkan baris ke dalam catatan dengan $REC
  • passing kedua untuk memicu pada instance pertama dari setiap nilai baru $REC sebagai batas rekaman (mengatur ulang $CURREC), setelah itu bergulir dalam idiom AWK asli mengenai rekaman untuk mengikuti $CURREC yang cocok.

Dalam file perantara, beberapa urutan angka desimal diikuti oleh pemisah (untuk alasan manusia, biasanya tab atau spasi tambahan) diuraikan (alias dipotong secara konseptual) sebagai out-of-band sehubungan dengan file dasar.

Monster tempel baris perintah

Bahkan terbatas pada baris perintah, mudah untuk memastikan bahwa file perantara tidak pernah mengenai disk. Anda hanya perlu menggunakan shell canggih seperti ZSH (favorit saya sendiri) yang mendukung substitusi proses:

paste <( <input.txt awk "BEGIN { R=0; N=0; } /Header pattern/ { N=1; } { R=R+N; N=0; print R; }" ) input.txt | awk -f yourscript.awk 

Mari buat satu baris itu lebih cocok untuk eksposisi:

P="/Header pattern/"
X="BEGIN { R=0; N=0; } $P { N=1; } { R=R+N; N=0; print R; }"
paste <( <input.txt awk $X ) input.txt | awk -f yourscript.awk 

Ini memulai tiga proses:skrip AWK inline sepele, paste , dan skrip AWK yang benar-benar ingin Anda jalankan.

Di belakang layar, <() konstruksi baris perintah membuat pipa bernama dan meneruskan nama pipa untuk ditempelkan sebagai nama file input pertamanya. Untuk paste file input kedua, kami memberinya nama file input asli kami (dengan demikian file ini dibaca secara berurutan, secara paralel, oleh dua proses berbeda, yang akan menggunakan paling banyak satu di antaranya baca dari disk, jika file masukan dingin).

Pipa bernama ajaib di tengah adalah FIFO dalam memori yang mungkin dikelola oleh Unix kuno dengan ukuran rata-rata sekitar 16 kB (sebentar-sebentar menjeda paste memproses jika yourscript.awk prosesnya lamban dalam menguras FIFO ini kembali).

Mungkin Unix modern melempar buffer yang lebih besar di sana karena itu bisa, tetapi itu jelas bukan sumber daya langka yang harus Anda khawatirkan, sampai Anda menulis benar-benar pertama Anda baris perintah lanjutan dengan pengalihan proses yang melibatkan ratusan atau ribuan :-)

Pertimbangan kinerja tambahan

Pada CPU modern, ketiga proses ini dapat dengan mudah dijalankan pada inti yang terpisah.

Dua yang pertama dari proses ini berbatasan dengan yang benar-benar sepele:skrip AWK dengan satu pola yang cocok dan beberapa pembukuan kecil, tempel disebut dengan dua argumen. yourscript.awk akan sulit ditekan untuk berlari lebih cepat dari ini.

Apa, mesin pengembangan Anda tidak memiliki core yang dimuat ringan untuk membuat pola solusi master shell-master ini hampir gratis di domain eksekusi?

Dering, dering.

Halo?

Hei, ini untukmu. 2018 baru saja menelepon, dan ingin masalahnya kembali.

2020 secara resmi adalah penangguhan hukuman MTV:Begitulah yang kami suka, pipa ajaib tanpa biaya dan inti gratis. Belum lagi vendor chip TLA tertentu yang mengguncang ruang akhir-akhir ini.

Sebagai pertimbangan kinerja akhir, jika Anda tidak ingin overhead penguraian nomor rekaman aktual:

X="BEGIN { N=0; } $P { N=1; } { print N; N=0; }"

Sekarang file perantara dalam-FIFO Anda dianotasi hanya dengan dua karakter tambahan yang ditambahkan di awal setiap baris ('0' atau '1' dan karakter pemisah default ditambahkan dengan paste ), dengan '1' menandai baris pertama dalam catatan.

FIFO bernama

Di bawah tenda, ini tidak berbeda dengan FIFO ajaib yang dibuat oleh Unix saat Anda menulis perintah pipa normal:

cat file | proc1 | proc2 | proc2 

Tiga pipa tanpa nama (dan seluruh proses dikhususkan untuk cat Anda bahkan tidak perlu).

Sangat disayangkan bahwa yang benar-benar luar biasa kenyamanan aliran stdin/stdout default seperti yang diatur sebelumnya oleh shell mengaburkan kenyataan bahwa paste $magictemppipe1 $magictemppipe2 tidak menanggung pertimbangan kinerja tambahan yang perlu dipikirkan, dalam 99% dari semua kasus.

"Gunakan <() Sendi Y, Luke."

Refleks naluriah Anda terhadap dekomposisi semantik alami dalam domain masalah akan sangat bermanfaat.

Jika ada yang punya akal untuk menamai konstruk shell <() sebagai operator YODA di tempat pertama, saya menduga itu akan ditekan ke layanan universal setidaknya satu dekade yang lalu.


Ini bisa menjadi cara:

$ awk '$1=="BB" && $2>1 {print f} {f=$1}' file
AAAAAAAAAAAAA

Penjelasan

  • $1=="BB" && $2>1 {print f} jika bidang pertama persis BB dan bidang ke-2 lebih besar dari 1 , lalu cetak f , nilai tersimpan.
  • {f=$1} simpan baris saat ini di f , sehingga dapat diakses saat membaca baris berikutnya.

Linux
  1. Cetak Dua File Dalam Dua Kolom?

  2. Cetak Baris Sebelumnya Setelah Pencocokan Pola Menggunakan Sed?

  3. Kotak Sibuk Membaca File Baris demi Baris?

  1. Cetak baris terakhir file, dari CLI

  2. perintah cut atau awk untuk mencetak bidang pertama dari baris pertama

  3. unix - membagi file .gz besar per baris

  1. Cat Line X Ke Line Y Pada File Besar?

  2. Bagaimana Cara Cat File Dari Awk?

  3. Tidak Dapat Menemukan File Untuk Ditambal Pada Baris Input 3?