Print Matching line dan nth line dari baris yang cocok

18

Saya mencoba untuk mencetak baris yang cocok dan baris ke-4 dari baris yang cocok (baris yang berisi ekspresi yang saya cari).

Saya telah menggunakan kode berikut: sed -n 's/^[ \t]*//; /img class=\"devil_icon/,4p' input.txt

Tapi ini hanya mencetak garis yang cocok.

Ini hanya mencetak baris ke-4. awk 'c&&!--c;/img class=\"devil_icon/{c=4}' input.txt

Saya perlu mencetak baris yang cocok dan baris ke-4 saja.

debal
sumber
Gunakan egrep "pattern" -A4
Valentin Bajrami
@ val0x00ff yang mencetak garis di antara juga .. yaitu: ia mencetak 4 baris berikutnya mulai dari garis yang cocok
debal
Anda mengatakan "Saya mencoba untuk mencetak baris yang cocok dan baris ke-4 dari baris yang cocok". Ini grep -A 4 "pattern" file | sed -n '4p'memang melakukan apa yang Anda inginkan, kecuali saya salah paham dengan Anda
Valentin Bajrami
tidak, tidak. Output dari kode di atas adalah </td>yang bukan baris ke-4
debal

Jawaban:

18

Dalam awk, Anda akan melakukannya sebagai berikut

awk '/pattern/{nr[NR]; nr[NR+4]}; NR in nr' file > new_file`

atau

awk '/pattern/{print; nr[NR+4]; next}; NR in nr' file > new_file`

Penjelasan

Solusi pertama menemukan semua baris yang cocok pattern. Ketika menemukan kecocokan, ia menyimpan nomor rekaman ( NR) dalam array nr. Ini juga menyimpan catatan ke-4 dari NRdalam array yang sama. Ini dilakukan oleh nr[NR+4]. Setiap record ( NR) kemudian diperiksa untuk melihat apakah ada dalam nrarray, jika demikian record dicetak.

Solusi kedua bekerja pada dasarnya dengan cara yang sama, kecuali ketika bertemu dengan patternitu mencetak garis itu, dan kemudian menyimpan catatan ke-4 di depannya dalam array nr, kemudian pergi ke catatan berikutnya. Kemudian ketika awkmenemukan catatan ke-4 ini, NR in nrblok akan dieksekusi dan mencetak catatan +4 ini setelahnya.

Contoh

Berikut ini contoh file data sample.txt,.

$ cat sample.txt 
1
2
3
4 blah
5
6
7
8
9
10 blah
11
12
13
14
15
16

Menggunakan solusi 1:

$ awk '/blah/{nr[NR]; nr[NR+4]}; NR in nr' sample.txt 
4 blah
8
10 blah
14

Menggunakan solusi ke-2:

$ awk '/blah/{print; nr[NR+4]; next}; NR in nr' sample.txt 
4 blah
8
10 blah
14
Valentin Bajrami
sumber
3
Bagus, +1. Anda menggunakan banyak awkpintasan di sini, dapatkah Anda menambahkan penjelasan singkat (hal-hal seperti cetak tersirat dalam awk dan bahwa array asosiatif dll)?
terdon
a setuju dengan @terdon tolong bisa jelaskan sedikit kode.
debal
@slm Terima kasih telah meningkatkan dan memberikan jawaban lengkap!
Valentin Bajrami
1
Terima kasih atas jawabannya, saya juga belajar sesuatu yang baru dengannya.
slm
4
sed -n 's/^[ \t]*/; /img class=\"devil_icon/,+4 { 3,5d ; p }' input.txt

Saya hanya menambahkan penghapusan garis yang sesuai, sebelum dicetak { 3,5d ; p }.

Drav Sloan
sumber
ekspresi Anda menghasilkan kesalahan: sed: -e expression #1, char 18: unknown option to s'`
mineral
4

Anda dapat mencoba -Aopsi dengan grep, yang menentukan berapa banyak garis setelah garis yang cocok harus dicetak. Pasangkan ini dengan sed, dan Anda akan mendapatkan garis yang diperlukan.

grep -A 4 pattern input.txt | sed -e '2,4d'

Dengan menggunakan sed, kami menghapus dari baris kedua hingga keempat.

Barun
sumber
3
Ini mengasumsikan kecocokan tunggal patterndalam file.
terdon
2

Inilah cara di Perl yang dapat menangani jumlah baris yang cocok secara acak:

perl -ne '/pattern/ && do{$c=$.; print}; $.==$c+4 && print' file > new_file`

Dalam Perl. variabel khusus $.adalah nomor baris saat ini. Jadi, setiap kali saya menemukan garis yang cocok pattern, saya mencetaknya dan menyimpan nomor barisnya sebagai $c. Saya kemudian mencetak lagi ketika nomor baris saat ini adalah 4 lebih dari yang dicetak sebelumnya.

terdon
sumber
0
awk 'c&&!--c;/img class=\"devil_icon/{c=4};/img class=\"devil_icon/' input.txt

Anda pada dasarnya mencari dan mengganti. Anda dapat menambahkan hanya menemukan ke dalam perintah yang sama dan itu akan mencetak keduanya :)

awk 'c&&!--c;/pattern/{c=4};/pattern/' input.txt
bacoNx1000
sumber