Saat menggunakan awk / pattern / {print “text”} / patern / {print “”} apakah ada pola ELSE?


22

Katakanlah saya memiliki file teks seperti:

R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

Saya ingin menggunakan awkuntuk memproses garis-garis ini secara berbeda, seperti

awk '/R1/ { print "=>" $0} /R2/ { print "*" $0} '

dan saya juga ingin mencetak semua sisa baris (tanpa membuat duplikat dari baris yang sudah saya proses), pada dasarnya saya perlu /ELSE/ { print $0}di akhir awkbaris saya .

Apakah ada hal seperti itu?

Jawaban:


27

Pendekatan Sederhana dengan awk

awk '/R1/ {print "=>" $0;next} /R2/{print "*" $0;next} 1' text.file

[jaypal:~/Temp] cat text.file 
R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

[jaypal:~/Temp] awk '/R1/ { print "=>" $0;next} /R2/{print "*" $0;next}1' text.file
=>R1 12 324 3453 36 457 4 7 8
*R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242
[jaypal:~/Temp] 

Pernyataan Breakout of Pattern {Action}:

  • /R1/ { print "=>" $0;next}: Ini berarti garis yang memiliki /R1/tindakan pencetakan =>akan dilakukan. nextberarti sisa pernyataan awk akan diabaikan dan baris berikutnya akan dilihat.

  • /R2/{print "*" $0;next}: Ini berarti garis yang sesuai pattern /R2/dengan tindakan pencetakan *akan dilakukan. Saat awkpemrosesan dimulai, pattern {action}pernyataan pertama akan diabaikan karena pattern /R1/tidak akan benar untuk baris yang dimiliki /R2/. Jadi pattern {action}pernyataan kedua akan dilakukan di telepon. nextlagi-lagi akan berarti bahwa kami tidak ingin pemrosesan lagi dan awksepatutnya pergi ke baris berikutnya.

  • 1mencetak semua garis. Ketika suatu kondisi disediakan tanpa {action}, awk akan digunakan secara default {print}. Di sini kondisinya 1ditafsirkan sebagai benar, sehingga selalu berhasil. Jika kita sampai pada titik ini, itu karena pernyataan pertama dan kedua pattern {action}diabaikan atau diabaikan (untuk baris yang tidak mengandung /R1/dan /R2/), sehingga tindakan cetak default akan dilakukan untuk baris yang tersisa.


Tampaknya menjalankan paling cepat semua solusi yang diposting.
Chris Down

1
Saya tidak yakin gula sintaksis adalah istilah yang tepat di sini ... Itu hanya sintaksis.
Daniel Hershcovich

7

awkmengimplementasikan tersangka yang biasa ketika datang ke kondisional. Sebaiknya gunakan printfalih-alih printuntuk pekerjaan yang ingin Anda lakukan saat pertandingan.

awk '{ if (/^R1/) { printf("=> %s\n", $0) } else if (/^R2/) { printf("* %s\n", $0) } else { print $0 } }'

Anda tidak benar-benar membutuhkan if-then-elseini.
jaypal singh

1
Meskipun ini bekerja dengan sangat baik, itu tidak idiomatis. Penggunaan bijaksana nextadalah alat penting dalam pemrograman awk.
dmckee

2
Saya tidak mengerti gunanya menggunakan di printfsini. Satu-satunya keuntungan (kecuali Anda melakukan pemformatan yang lebih menarik daripada gabungan) adalah tidak menambah baris baru, yang tidak relevan di sini.
Gilles 'SANGAT berhenti menjadi jahat'

1
Itu hasil yang berlawanan dengan intuisi dan mengejutkan. Unadorned printhanya memiliki keluaran $0sedangkan printfharus mem-parsing format string.
jw013

5

Chris Down sudah menunjukkan bagaimana Anda bisa mendapatkan yang lain untuk regexps dengan menggunakan pernyataan 'jika' eksplisit di blok. Anda juga bisa mendapatkan efek yang sama dengan beberapa cara lain, meskipun solusinya mungkin lebih baik.

Pertama adalah menulis regex ketiga yang hanya akan cocok dengan teks yang tidak cocok dengan yang lain, dalam kasus Anda, ini akan terlihat seperti ini:

awk '/^R1/ { print "=>" $0}
     /^R2/ { print "*" $0}
     /^[^R]/ || /^R[^12]/ { print $0 } '

Catatan, ini menggunakan regexps berlabuh - ^ di awal regexps hanya akan cocok pada awal baris - pola asli Anda tidak melakukan ini, yang memperlambat pencocokan sedikit karena akan memeriksa semua karakter pada baris daripada melewatkan hingga baris berikutnya. Kasus ketiga ("lain") akan cocok dengan garis yang dimulai dengan beberapa karakter yang bukan 'R' ([^ R]) atau yang dimulai dengan 'R' diikuti oleh karakter yang bukan '1' atau ' 2 '(R [^ 12]). Dua arti ^ yang berbeda agak membingungkan, tetapi kesalahan itu dibuat sejak lama dan tidak akan berubah dalam waktu dekat.

Untuk menggunakan regexps komplementer, mereka benar-benar perlu berlabuh, karena jika [^ R] akan cocok misalnya 1 yang mengikutinya. Untuk regexps yang sangat sederhana seperti yang Anda miliki, pendekatan ini bisa bermanfaat, tetapi ketika regexps menjadi lebih kompleks, pendekatan ini akan menjadi tidak terkelola. Sebagai gantinya, Anda dapat menggunakan variabel status untuk setiap baris, seperti ini:

awk '{ handled = 0 }
     /^R1/ { print "=>" $0; handled = 1}
     /^R2/ { print "*" $0; handled = 1}
     { if (!handled) print $0 } '

Set ini ditangani ke nol untuk setiap baris baru, lalu ke 1 jika cocok dengan salah satu dari kedua regexps, dan akhirnya, jika masih nol, jalankan cetakan $ 0.


Perlu dicatat bahwa pada file besar keduanya kurang efisien daripada menggunakan kondisional (seperti yang ditunjukkan di sini ). rfilehanya 10.000 baris dataset kuesioner yang diulang.
Chris Down

4
if (!handled)Huek! Gunakan nextuntuk berhenti mempertimbangkan tindakan lain.
dmckee

+1 untuk if (!handled). Solusi umum, fleksibel, dapat digunakan kembali adalah baik. Bagaimana jika orang berikutnya yang memiliki pertanyaan ini ingin melakukan lebih banyak pemrosesan setelah pencetakan? Jawaban dengan nexttidak mendukung itu.
Scott
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.