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 persisBB
dan bidang ke-2 lebih besar dari1
, lalu cetakf
, nilai tersimpan.{f=$1}
simpan baris saat ini dif
, sehingga dapat diakses saat membaca baris berikutnya.