เมื่อใช้ awk / pattern / {print“ text”} / patern / {print“”} มีรูปแบบ ELSE หรือไม่


22

สมมติว่าฉันมีไฟล์ข้อความเช่น:

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

ฉันต้องการที่จะใช้awkในการประมวลผลบรรทัดเหล่านี้แตกต่างกันเช่น

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

และฉันต้องการพิมพ์บรรทัดที่เหลือทั้งหมดด้วย (โดยไม่ต้องทำซ้ำของบรรทัดที่ฉันได้ประมวลผลแล้ว) โดยทั่วไปฉันต้องการ /ELSE/ { print $0}ที่ส่วนท้ายของawkบรรทัด

มีอะไรแบบนี้เหรอ?

คำตอบ:


27

แนวทางแบบง่าย ๆ ด้วย 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] 

คำสั่ง breakout ของรูปแบบ {Action}:

  • /R1/ { print "=>" $0;next}: นี่หมายถึงเส้นที่มี/R1/การกระทำของการพิมพ์=>จะเสร็จสิ้น nextหมายถึงคำสั่ง awk ที่เหลือจะถูกละเว้นและบรรทัดถัดไปจะถูกดู

  • /R2/{print "*" $0;next}: นี่หมายถึงเส้นที่ตรงกับpattern /R2/การกระทำของการพิมพ์*จะเสร็จสิ้น เมื่อawkประมวลผลเริ่มต้นครั้งแรกที่pattern {action}คำสั่งจะถูกละเว้นเป็นจะไม่เป็นจริงสำหรับสายที่มีpattern /R1/ /R2/ดังนั้นpattern {action}คำสั่งที่สองจะทำในบรรทัด nextจะหมายความว่าเราไม่ต้องการการประมวลผลawkอีกต่อไปและจะไปที่บรรทัดถัดไป

  • 1พิมพ์ทุกบรรทัด เมื่อเพียงเงื่อนไขที่จะมาพร้อมกับไม่มี{action}, awk {print}ค่าเริ่มต้นจากการใช้ นี่คือเงื่อนไข1ที่ถูกตีความว่าเป็นจริงดังนั้นจึงประสบความสำเร็จเสมอ หากเรามาถึงจุดนี้นั่นเป็นเพราะpattern {action}ข้อความสั่งแรกและประโยคที่สองถูกละเว้นหรือผ่านไป (สำหรับบรรทัดที่ไม่มี/R1/และ/R2/) ดังนั้นการดำเนินการพิมพ์เริ่มต้นจะทำสำหรับบรรทัดที่เหลือ


ดูเหมือนว่าจะเรียกใช้โซลูชันที่โพสต์ทั้งหมดเร็วที่สุด
Chris Down

1
ฉันไม่แน่ใจว่าน้ำตาล syntacticเป็นคำที่เหมาะสมที่นี่ ... มันเป็นเพียงไวยากรณ์
Daniel Hershcovich

7

awkดำเนินการผู้ต้องสงสัยตามปกติเมื่อมันมาถึงเงื่อนไข เป็นความคิดที่ดีที่จะใช้printfแทนprintงานที่คุณต้องการทำในสิ่งที่ตรงกัน

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

คุณไม่ต้องการif-then-elseสิ่งนี้จริงๆ
jaypal singh

1
แม้ว่ามันจะใช้งานได้ดีอย่างสมบูรณ์ แต่ก็ไม่ได้เป็นสำนวน การใช้อย่างรอบคอบnextเป็นเครื่องมือสำคัญในการเขียนโปรแกรม awk
dmckee

2
ฉันไม่เข้าใจจุดที่ใช้printfที่นี่ ข้อได้เปรียบเพียงอย่างเดียวของมัน (ยกเว้นว่าคุณกำลังทำการจัดรูปแบบที่น่าสนใจกว่าการต่อข้อมูลแบบย่อ) ก็คือมันไม่ได้เพิ่มบรรทัดใหม่ซึ่งไม่เกี่ยวข้องกับที่นี่
Gilles 'หยุดความชั่วร้าย'

1
นั่นเป็นผลลัพธ์ที่ตอบโต้ได้ง่ายและน่าประหลาดใจ ไม่มีเครื่องตกแต่งprintเท่านั้นที่จะส่งออก$0ในขณะที่printfมีการแยกสตริงรูปแบบ
jw013

5

Chris Down ได้แสดงให้เห็นแล้วว่าคุณสามารถรับ regexps ได้อย่างไรโดยใช้คำสั่ง 'if' ในบล็อกอย่างชัดเจน คุณสามารถได้รับผลเช่นเดียวกันในบางวิธีแม้ว่าวิธีแก้ปัญหาของเขาอาจจะดีกว่า

หนึ่งคือการเขียน regex ที่สามที่จะตรงกับข้อความที่ไม่ตรงกับคนอื่น ๆ ในกรณีของคุณนี้จะมีลักษณะดังนี้

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

หมายเหตุสิ่งนี้ใช้ regexps ที่ยึดไว้ - ^ ที่จุดเริ่มต้นของ regexps จะจับคู่ที่จุดเริ่มต้นของบรรทัดเท่านั้น - รูปแบบดั้งเดิมของคุณไม่ได้ทำเช่นนี้ซึ่งช้ากว่าการจับคู่เล็กน้อยเนื่องจากมันจะตรวจสอบอักขระทั้งหมดในบรรทัดมากกว่า ข้ามไปจนถึงบรรทัดถัดไป กรณีที่สาม ("else") จะตรงกับบรรทัดที่ขึ้นต้นด้วยอักขระบางตัวที่ไม่ใช่ 'R' ([^ R]) หรือที่ขึ้นต้นด้วย 'R' ตามด้วยอักขระที่ไม่ใช่ '1' หรือ ' 2 '(R [^ 12]) ^ ความหมายที่แตกต่างกันสองอย่างของ ^ ค่อนข้างสับสน แต่ความผิดพลาดนั้นทำมานานแล้วและจะไม่เปลี่ยนแปลงในไม่ช้า

ในการใช้ regexps เสริมพวกเขาจำเป็นต้องได้รับการยึดจริงมิฉะนั้น [^ R] จะจับคู่เช่น 1 ที่ตามมา สำหรับ regexps ง่าย ๆ อย่างที่คุณมีวิธีนี้จะมีประโยชน์ แต่เมื่อ regexps มีความซับซ้อนมากขึ้นวิธีนี้จะไม่สามารถจัดการได้ แต่คุณสามารถใช้ตัวแปรสถานะสำหรับแต่ละบรรทัดเช่นนี้

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

ชุดนี้จัดการให้เป็นศูนย์สำหรับแต่ละบรรทัดใหม่จากนั้นเป็น 1 หากตรงกับหนึ่งในสอง regexps และในที่สุดหากยังคงเป็นศูนย์ดำเนินการพิมพ์ $ 0


ควรสังเกตว่าไฟล์ขนาดใหญ่ทั้งคู่มีประสิทธิภาพน้อยกว่าการใช้เงื่อนไข (ดังที่แสดงไว้ที่นี่ ) rfileเป็นเพียง 10,000 บรรทัดของชุดข้อมูลของผู้ถามซ้ำ
Chris Down

4
if (!handled)yuck! ใช้nextเพื่อหยุดพิจารณาการกระทำอื่น ๆ
dmckee

+1 if (!handled)สำหรับ โซลูชันทั่วไปที่ยืดหยุ่นและสามารถนำกลับมาใช้ใหม่ได้นั้นดี จะเป็นอย่างไรถ้าบุคคลต่อไปที่มีคำถามนี้ต้องการดำเนินการเพิ่มเติมหลังจากการพิมพ์ คำตอบที่nextไม่สนับสนุนนั้น
สกอตต์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.