จำกัด เอาต์พุต grep เป็นบรรทัดสั้น ๆ


8

ฉันมักใช้ grep เพื่อค้นหาไฟล์ที่มีรายการบางรายการเช่นนี้:

grep -R 'MyClassName'

สิ่งที่ดีคือมันคืนไฟล์เนื้อหาและทำเครื่องหมายสตริงที่พบเป็นสีแดง สิ่งที่ไม่ดีคือฉันยังมีไฟล์ขนาดใหญ่ที่เขียนข้อความทั้งหมดในบรรทัดเดียวขนาดใหญ่ ตอนนี้ grep เอาต์พุตมากเกินไปเมื่อค้นหาข้อความภายในไฟล์ขนาดใหญ่เหล่านั้น มีวิธี จำกัด ผลลัพธ์ให้เช่น 5 คำไปทางซ้ายและไปทางขวาหรือไม่ หรืออาจ จำกัด ผลลัพธ์ให้เหลือ 30 ตัวอักษรไปทางซ้ายและไปทางขวา?


3
ท่อผลลัพธ์ของคุณผ่านcut
Rinzwind

สมมุติว่ารูปแบบที่คุณต้องการอยู่ที่ตำแหน่ง 50 แต่คุณบอกว่าคุณต้องการแค่ 30 ตัวอักษรคุณต้องการทำอะไร? ละเว้นบรรทัดนั้นหรือรวมไว้ในเอาต์พุต แต่ตัดแต่งหรือไม่ สิ่งที่คุณต้องการ จำกัด - การค้นหาหรือเส้นตัวเอง?
Sergiy Kolodyazhnyy

1
@ Rinzwind ฉันไม่เข้าใจสิ่งที่คุณต้องการที่จะประสบความสำเร็จcutเพราะมันแยกจากตัวคั่นหรือตามจำนวนตัวอักษรเท่านั้น แม้ว่าเมื่อฉันพบบรรทัดด้วยMyClassNameอาจเป็นที่ใดก็ได้ในบรรทัดและไม่อยู่ในตำแหน่งเดียวกันเสมอไป นอกจากนี้อาจมีการเปลี่ยนแปลงของตัวละครในด้านหน้าและด้านหลังของมันซึ่งแบ่งความเป็นไปได้ที่จะแยกโดยตัวคั่น
โสกราตีส

1
@SergiyKolodyazhnyy เมื่อพบบรรทัดบวกด้วยMyClassNameฉันต้องการได้รับผลลัพธ์จากชื่อไฟล์และอักขระ x ทางด้านซ้ายและด้านขวา x คือหมายเลขใด ๆ ที่ฉันให้ตัวอย่าง 30 ส่วนที่เหลือของเนื้อหาไฟล์จะถูกละเว้น นี่คือการรับบริบทของไฟล์ที่ตรงกันและ จำกัด การโอเวอร์โหลด
โสกราตีส

1
@Rinzwind ตัวคั่นที่กำหนดเองประเภทใดที่คุณแนะนำด้วยcutหากมีสามไฟล์ที่มีอินพุตต่อไปนี้: oiadfaosuoianavMyClassNameionaernaldfajdและ/(/&%%§%/(§(/MyClassName&((/$/$/(§/$&และpublic class MyClassName { public static void main(String[] args) { } }?
โสกราตีส

คำตอบ:


15

grepตัวเองมีเพียงตัวเลือกสำหรับบริบทตามบรรทัด แนะนำเป็นทางเลือกโดยโพสต์ SU นี้ :

วิธีแก้ปัญหาคือการเปิดใช้งานตัวเลือก 'จับคู่เท่านั้น' และจากนั้นใช้พลังของ RegExp เพื่อ grep มากกว่าข้อความของคุณ:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}" ./filepath

แน่นอนถ้าคุณใช้การไฮไลต์สีคุณสามารถ grep อีกครั้งเพื่อให้ตรงกับสีจริงเท่านั้น:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}"  ./filepath | grep "WHAT_I_M_SEARCHING"

เป็นอีกทางเลือกหนึ่งฉันขอแนะนำให้คุณfoldอ่านข้อความแล้วทำการ grepping ตัวอย่างเช่น:

fold -sw 80 input.txt | grep ...

-sตัวเลือกที่จะทำให้foldคำผลักดันในบรรทัดถัดไปแทนการทำลายในระหว่าง

หรือใช้วิธีอื่นเพื่อแยกอินพุตในบรรทัดตามโครงสร้างของอินพุตของคุณ (ตัวอย่างเช่นการโพสต์ SU จัดการกับ JSON ดังนั้นการใช้jqฯลฯ เพื่อพิมพ์สวยและgrep... หรือเพียงแค่ใช้jqในการทำการกรองด้วยตัวเอง ... จะดีกว่าทั้งสองทางเลือกดังกล่าวข้างต้น)


เมธอด awk ของ GNU นี้อาจเร็วกว่า:

gawk -v n=50 -v RS='MyClassName' '
  FNR > 1 { printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)}
  {p = substr($0, length - n); prt = RT}
' input.txt
  • บอก awk เพื่อแยกบันทึกในรูปแบบที่เราสนใจ ( -v RS=...) และจำนวนอักขระในบริบท ( -v n=...)
  • แต่ละเร็กคอร์ดหลังจากเร็กคอร์ดแรก ( FNR > 1) คือหนึ่งที่ awk พบการจับคู่สำหรับรูปแบบ
  • ดังนั้นเราจึงพิมพ์nตัวอักษรต่อท้ายจากบรรทัดก่อนหน้า ( p) และnตัวอักษรนำจากบรรทัดปัจจุบัน ( substr($0, 0, n)) พร้อมกับข้อความที่ตรงกันสำหรับบรรทัดก่อนหน้า (ซึ่งคือprt)
    • เราตั้งค่าpและprt หลังการพิมพ์ดังนั้นค่าที่เราตั้งไว้จะถูกใช้โดยบรรทัดถัดไป
    • RT เป็น GNUism และนี่คือเหตุผลว่าทำไม GNU ถึงเฉพาะเจาะจง

สำหรับการค้นหาแบบเรียกซ้ำอาจจะ:

find . -type f -exec gawk -v n=50 -v RS='MyClassName' 'FNR>1{printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)} {p = substr($0, length-n); prt = RT}' {} +

2
ตกลงมันใช้งานได้ Seems Regex เป็นวิธีที่ถูกต้องดังนั้นขอบคุณสำหรับสิ่งนั้น เวลาในการประมวลผลค่อนข้างใหญ่ ไม่มี Regex เช่นเดียวกับในโพสต์ของฉันมันใช้เวลา 4.912 วินาทีและ Regex เหมือนกับในโพสต์ของคุณจะใช้เวลา 339.312 วินาที
โสกราตีส

1
@Socrates ดูว่าวิธีการ awk ฉันเพิ่มดังกล่าวข้างต้นดำเนินการที่ดีกว่า
Muru

1
วิธีสามารถนำมาใช้เฉพาะในกรณีที่คุณมีความแน่ใจว่าการสืบค้นสตริงไม่ปรากฏที่ชายแดนมิฉะนั้นก็จะได้รับการซ่อนไว้โดยfold grep
Melebius

1
@muru gawkขอบคุณสำหรับคำแนะนำของคุณด้วย น่าเสียดายที่คำสั่งที่แนะนำพร้อมfindผลลัพธ์แบบสุ่มและไม่มีชื่อไฟล์เมื่อดำเนินการในระบบของฉัน นอกจากนี้ฉันไม่คล่องพอที่awkจะวิเคราะห์คำสั่งอย่างถูกต้อง ปัจจุบัน Regex ร่วมกับการgrepแก้ปัญหาอาจไม่เร็ว แต่เชื่อถือได้ อีกครั้งขอบคุณมาก
โสกราตีส

1
@ โสกราตีสฉันคิดว่าฉันจัดการเพื่อแก้ไขคำสั่ง awk แบบจำลองทางจิตของฉันผิดเกี่ยวกับบรรทัดRTและคำนำหน้า ฯลฯ ที่จะใช้
muru

1

การใช้การจับคู่อย่างเดียวร่วมกับตัวเลือกอื่น ๆ (ดูด้านล่าง) อาจใกล้เคียงกับสิ่งที่คุณกำลังค้นหาโดยไม่ต้องประมวลผลค่าใช้จ่ายของ regex ที่กล่าวถึงในคำตอบอื่น

grep -RnHo 'MyClassName'
  • nเอาต์พุตตัวเลขแสดงหมายเลขบรรทัดของการจับคู่
  • Hชื่อไฟล์แสดงชื่อไฟล์ที่จุดเริ่มต้นของบรรทัดของการแข่งขัน
  • o การแข่งขันเท่านั้นแสดงเฉพาะสตริง mathed ไม่ใช่ทั้งเส้น

ในขณะที่เป็นจริงที่พบผลลัพธ์เร็วขึ้นมากมีข้อมูลที่ขาดหายไป เส้นทางของไฟล์จะแสดงหมายเลขบรรทัดจะปรากฏ MyClassNameแต่การส่งออกข้อความที่เป็นเพียงการค้นหาครั้งแรกของฉัน ดังนั้นบริบทจึงหายไป
โสกราตีส

grep -RnHo "MyClassName"และgrep -Rno "MyClassName"มีเอาต์พุตเดียวกัน
โสกราตีส

@ เอาต์พุตโซคราตีไม่เหมือนกันหากไม่มีHในไดเรกทอรีเดียวกัน
Robert Riedl

การ-oตั้งค่าสถานะอาจน่าสนใจถ้า regex มีบางส่วนของตัวแปร สำหรับสตริงคงที่มันไม่มีประโยชน์ที่จะพิมพ์ในแต่ละครั้ง OP น่าจะสนใจในบริบทที่ใกล้ที่สุด
Melebius

1
@ โสกราตีสจริง - บริบทหายไป แต่ฉันคิดว่านั่นเป็นประเด็น จำกัด เอาต์พุตหรือไม่ คุณสามารถเพิ่มบริบทอีกครั้งโดยเพิ่มบรรทัดก่อน ( -B 1) หรือหลัง ( -A 1) ขออภัยที่ฉันไม่สามารถช่วยได้มากขึ้น
Robert Riedl
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.