grep เพื่อส่งคืนบรรทัด Nth และ Mth ก่อนและหลังการแข่งขัน


12

ฉันรู้ว่าด้วย grep ฉันสามารถใช้ฟิลด์-Aและ-Bดึงบรรทัดก่อนหน้าและถัดไปจากการแข่งขัน

อย่างไรก็ตามพวกเขาดึงทุกบรรทัดระหว่างการแข่งขันโดยมีการระบุหลายบรรทัด

grep -r -i -B 5 -A 5 "match" 

ผมอยากจะเพียง แต่ได้รับ 5 THสายก่อนการแข่งขันและ 5 THเส้นหลังการแข่งขันนอกเหนือไปจากเส้นตรงและไม่ได้รับสายระหว่าง

มีวิธีการทำเช่นนี้กับgrep?


1
คุณสามารถทำได้โดยการวางลงใน sed ฉันเพิ่งผ่านการทดสอบนี้และมันทำงาน แต่มันทำงานเฉพาะเมื่อมีการแข่งขันที่แน่นอน 1 ในแฟ้ม: grep -r -i -B 5 -A 5 "match" | sed -e 1b -e '$!d'
Terrance

@ Terrance ขอบคุณสำหรับข้อเสนอแนะตามที่คุณพูดถึงเนื่องจากฉันรวบรวม 1,000 บรรทัดนี้จะไม่ทำงาน
chollida

ฉันไม่คิดว่า grep จะทำงานด้วยตัวเอง ... ผมทำงานในสคริปต์ทุบตีสำหรับคุณ
โจชัว Besneatte

ไม่มีปัญหา! สนใจที่จะดูว่าคุณได้รับคำตอบอะไร =)
Terrance

นี่คือหนึ่งไฟล์หรือหลายไฟล์?
Joshua Besneatte

คำตอบ:


1

เครื่องมือที่คุณต้องการใช้เรียกว่าร่อน นี่คือ grep บนเตียรอยด์โดยทั่วไป grep ในแบบคู่ขนาน Sift มีตัวเลือกมากมายในการทำสิ่งที่คุณต้องการ - โดยเฉพาะเพื่อส่งคืนบรรทัดที่สัมพันธ์กับการจับคู่ซึ่งอาจ / ไม่อาจตามด้วย / นำหน้าด้วยข้อความบางส่วน

มันทำให้ฉันประหลาดใจว่าการร่อนไม่ใช่ gnu หลักเพราะมันเขียนในภาษาโก แต่ติดตั้งบน Linux ได้ดี ฝ่ายไอทีค้นหาคู่ขนานโดยใช้ข้อความ cpus จำนวนมากที่ grep ใช้เวลาทำสัปดาห์เดียวกัน

เว็บไซต์ร่อน - ดูตัวอย่าง


ยินดีต้อนรับสู่ AskUbuntu ขอบคุณสำหรับการตอบรับ คุณต้องให้ตัวอย่าง CLI ที่สามารถแก้ปัญหาเฉพาะนี้ได้แทนที่จะให้ลิงค์ไปยังเว็บไซต์ร่อน นี่เป็นคำถาม & คำตอบหลังจากนั้นทั้งหมดขอบคุณ
Bernard Wei Wei

12

ถ้า:

cat file
a
b
c
d
e
f match
g
h
i match
j
k
l
m
n
o

แล้ว:

awk '
    {line[NR] = $0} 
    /match/ {matched[NR]} 
    END {
        for (nr in matched)
            for (n=nr-5; n<=nr+5; n+=5) 
                print line[n]
    }
' file
a
f match
k
d
i match
n

+1 แต่คุณสามารถอธิบายความหมายของได้/match/ {matched[NR]}อย่างไร ฉันไม่เคยเห็นอาร์เรย์หรือตัวแปรเป็นคำสั่งทั้งหมด มันคือการใส่หมายเลขระเบียนปัจจุบันของแต่ละบรรทัดที่ตรงกันลงในอาร์เรย์
Joe

นี่คือความผิดปกติ awk: ถ้าคุณอ้างอิงองค์ประกอบอาร์เรย์โดยไม่มีการกำหนดคีย์นั้นจะถูกเพิ่มไปยังอาร์เรย์ (โดยไม่มีค่า) key in arrayแล้วที่สำคัญที่แสดงให้เห็นในการแสดงออก สิ่งที่ฉันทำคือการจำหมายเลขบรรทัดที่รูปแบบปรากฏขึ้น
เกล็นแจ็

6

นี่เป็นวิธีการแก้ปัญหาของ Glenn แต่ถูกนำไปใช้กับ Bash, Grep และ sed

grep -n match file |
    while IFS=: read nr _; do
        sed -ns "$((nr-5))p; $((nr))p; $((nr+5))p" file
    done

โปรดทราบว่าหมายเลขบรรทัดที่น้อยกว่า 1 จะทำให้เกิดข้อผิดพลาดและหมายเลขบรรทัดที่มากกว่าจำนวนบรรทัดในไฟล์จะไม่พิมพ์อะไรเลย

นี่เป็นเพียงขั้นต่ำเปล่า เพื่อให้ทำงานซ้ำและจัดการกับกรณีหมายเลขบรรทัดข้างต้นจะใช้เวลาทำ


6

grepมันไม่สามารถทำได้ด้วยเท่านั้น หากedเป็นตัวเลือก:

ed -s file << 'EOF' 
g/match/-5p\
+5p\
+5p
EOF  

โดยพื้นฐานแล้วสคริปต์บอกว่า: สำหรับทุกการแข่งขันของ / match / ให้พิมพ์บรรทัดที่ 5 ก่อนหน้านั้นจากนั้น 5 บรรทัดหลังจากนั้นแล้ว 5 บรรทัดหลังจากนั้น


5
@ubashu คุณคิดว่ามันจะมีประโยชน์มากกว่าสำหรับ OP ที่ให้แฟลตอย่างง่าย "มันไม่สามารถทำได้ด้วย grep" หรือไม่? ฉันให้สิ่งที่ฉันเชื่อว่าเป็นทางเลือกที่ดีในการแก้ปัญหาของ OP จากศูนย์ช่วยเหลือ: "มีคำถามอะไรถามโดยเฉพาะหรือไม่ตรวจสอบให้แน่ใจว่าคำตอบของคุณมี - หรือเป็นทางเลือกที่ทำงานได้คำตอบอาจเป็น 'ไม่ทำเช่นนั้น' แต่ควรรวม 'ลองใช้แทน' ."
JoL


5
@ubashu แม้ว่าจะไม่ใช่grepคำตอบคำตอบของ "คุณไม่สามารถทำได้ด้วย X แต่คุณสามารถทำได้กับ Y นี่คือวิธี" ยังคงเป็นคำตอบที่ถูกต้องเนื่องจากคุณไม่เพียง แต่ตอบคำถามของ OP แต่ยังให้ทางเลือกอื่น ที่จะทำงาน นี่เป็นคำตอบที่ถูกต้องที่นี่
Thomas Ward

5
awk '/match/{system("sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME)}' infile

ที่นี่เราจะใช้awk 's ฟังก์ชั่นที่จะเรียกภายนอกคำสั่งในการพิมพ์เส้นที่awkจับคู่กับรูปแบบที่มี 5 THเส้นก่อนและหลังการแข่งขันsystem(command)sedmatch

ไวยากรณ์เป็นเรื่องง่ายคุณเพียงแค่วางคำสั่งภายนอกไว้ในเครื่องหมายคำพูดคู่เช่นเดียวกับสวิตช์และหลบหนีสิ่งที่คุณต้องการส่งผ่านไปยังคำสั่งทุกอย่างที่เกี่ยวข้องกับawkตัวเลือกของตัวเองควรอยู่นอกเครื่องหมายคำพูด ดังนั้นด้านล่างsed :

"sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME

แปลเป็น:

sed -n "NR-5p; NRp; NR+5p" FILENAME

NRเป็นจำนวนบรรทัดที่จับคู่กับรูปแบบmatchและFILENAMEเป็นปัจจุบันของการประมวลผลชื่อไฟล์awkผ่านโดย


2

การใช้ไฟล์ข้อความตัวอย่างของ @ glenn และการใช้ Perl แทน awk:

$ perl -n0E 'say /(.*\n)(?=(?:.*\n){4}(.*match.*\n)(?:.*\n){4}(.*\n))/g' ex

จะให้ผลลัพธ์เดียวกัน แต่ทำงานได้เร็วขึ้น:

a
f match
k
d
i match
n

Joãoคุณจะแสดงในคิวการตรวจสอบ LQ และ @waltinator ลงมติให้ลบดังนั้นครั้งต่อไปจะเป็นบิตขนาดเล็กมากขึ้นอย่างละเอียด ... ;-) นอกจากนี้ 1 ที่จะได้รับคุณออกจากคิว LQ และ ... : P
Fabby

1
@JJoao คิวตรวจสอบคุณภาพต่ำ คำตอบของคุณอาจถูกหยิบขึ้นมาเพราะมันเป็นรหัส 90%
wjandrea

1
@Joao ตัวเลข 90% เป็นเพียงวิธีการอธิบายของฉัน ฉันไม่รู้ว่าใช้ฮิวริสติกแบบใด
wjandrea

1
Menos café, mais escrita! @JJoao : D ;-): D
Fabby

1
@Fabby: Sem café nada funciona: D - อาจจะปรากฏใน LCQ (= คิวกาแฟต่ำ)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.