อักขระ Grep ก่อนและหลังการแข่งขัน?


144

ใช้สิ่งนี้:

grep -A1 -B1 "test_pattern" file

จะสร้างหนึ่งบรรทัดก่อนและหลังรูปแบบที่ตรงกันในไฟล์ มีวิธีการแสดงไม่ใช่บรรทัด แต่มีจำนวนอักขระที่ระบุหรือไม่

เส้นในไฟล์ของฉันค่อนข้างใหญ่ดังนั้นฉันจึงไม่สนใจที่จะพิมพ์ทั้งบรรทัด แต่ให้สังเกตเฉพาะการจับคู่ในบริบทเท่านั้น ข้อเสนอแนะใด ๆ เกี่ยวกับวิธีการทำเช่นนี้?


1
ทำซ้ำของunix.stackexchange.com/q/163726ใกล้กับสำเนาของstackoverflow.com/q/2034799
sondra.kinsey

คำตอบ:


184

3 ตัวอักษรก่อนหน้าและ 4 ตัวอักษรหลัง

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and

5
คำตอบที่ดีสำหรับข้อมูลจำนวนเล็กน้อย แต่มันเริ่มช้าเมื่อคุณจับคู่> 100 ตัวอักษร - เช่นในไฟล์ xml ขนาดยักษ์ของฉันฉันต้องการ {1,200} ก่อนและหลังและมันช้าเกินกว่าจะใช้
Benubird

3
รุ่น awk โดย @amit_g นั้นเร็วกว่ามาก
ssobczak

6
ไม่สามารถใช้งานได้บน Mac OSX ดังนั้นจริงๆแล้วนี่ไม่ใช่วิธีการแก้ปัญหาที่มีอยู่อย่างกว้างขวาง รุ่น -E (รายการด้านล่าง) เป็นวิธีแก้ปัญหาที่ดีกว่า -P คืออะไร อ่านต่อ ... -P, --perl-regexp ตีความรูปแบบเป็นนิพจน์ปกติ Perl (PCRE ดูด้านล่าง) นี่คือการทดลองอย่างมากและ grep -P อาจเตือนถึงคุณลักษณะที่ยังไม่ได้ใช้งาน
Xofo

2
ใน OSX ติดตั้งผ่าน: และเรียกมันว่าbrew install homebrew/dupes/grep ggrep
kenorb

1
ตามที่ระบุโดย @Benubird สิ่งนี้จะไม่สามารถใช้กับไฟล์ขนาดใหญ่ที่มีสภาพแวดล้อมที่กว้างพอสมควรสำหรับเป้าหมายการจับคู่
matanster

113
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

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


1
คำตอบที่ดีน่าสนใจที่มีความยาว 2 ^ 8-1 ใน {} ดังนั้น{0,255}ผลงานจึง{0,256}มอบให้grep: invalid repetition count(s)
CodeMonkey

ดูเหมือนว่าจะมีประสิทธิภาพน้อยลงเมื่อฉันเพิ่มจำนวนตัวอักษรที่ตรงกัน (5 -> 25 -> 50) ความคิดใด ๆ
Adam Hughes

37

คุณสามารถใช้

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file

2
ใช้งานได้ดีแม้กับไฟล์ที่ค่อนข้างใหญ่
Touko

4
คุณจะใช้มันเพื่อค้นหารายการที่ตรงกันหลายรายการได้อย่างไร?
koox00

1
หมายเลขแรกในคู่ที่มีวงเล็บเหลี่ยมคืออะไร เช่นเดียวกับ 0s ใน "grep -E -o". {0,5} test_pattern. {0,5} "test.txt"?
แฟน Lew Rockwell

มันเร็วกว่าจริงๆ แต่ไม่แม่นยำเท่าคำตอบของ @ ekse
Abdollah

24

คุณหมายถึงเช่นนี้:

grep -o '.\{0,20\}test_pattern.\{0,20\}' file

?

test_patternที่จะพิมพ์ได้ถึงยี่สิบตัวอักษรบนด้านข้างของทั้ง \{0,20\}สัญกรณ์เป็นเหมือน*แต่ระบุเป็นศูนย์ถึงยี่สิบซ้ำแทนที่จะเป็นศูนย์หรือ more.The -oกล่าวว่าเพื่อแสดงเฉพาะการแข่งขันของตัวเองมากกว่าสายทั้งหมด


คำสั่งนี้ใช้ไม่ได้สำหรับฉัน:grep: Invalid content of \{\}
Alexander Pravdin

0

ด้วยgawk, คุณสามารถใช้ฟังก์ชั่นการจับคู่:

    x="hey there how are you"
    echo "$x" |awk --re-interval '{match($0,/(.{4})how(.{4})/,a);print a[1],a[2]}'
    ere   are

หากคุณตกลงperlโซลูชันที่ยืดหยุ่นมากขึ้น: การติดตามจะพิมพ์อักขระสามตัวก่อนรูปแบบตามด้วยรูปแบบจริงและจากนั้น 5 อักขระหลังรูปแบบ

echo hey there how are you |perl -lne 'print "$1$2$3" if /(.{3})(there)(.{5})/'
ey there how

สิ่งนี้สามารถนำไปใช้กับคำแทนที่จะเป็นแค่ตัวอักษรการติดตามจะพิมพ์หนึ่งคำก่อนที่จะจับคู่สตริงที่แท้จริง

echo hey there how are you |perl -lne 'print $1 if /(\w+) there/'
hey

การติดตามจะพิมพ์หนึ่งคำหลังจากรูปแบบ:

echo hey there how are you |perl -lne 'print $2 if /(\w+) there (\w+)/'
how

การติดตามต่อไปนี้จะพิมพ์หนึ่งคำก่อนรูปแบบจากนั้นคำที่แท้จริงและจากนั้นหนึ่งคำต่อจากรูปแบบ:

echo hey there how are you |perl -lne 'print "$1$2$3" if /(\w+)( there )(\w+)/'
hey there how

0

คุณสามารถใช้ grep regexp สำหรับการค้นหา + grep ที่สองเพื่อเน้น

echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}' | grep string

23_string_and

ป้อนคำอธิบายรูปภาพที่นี่


0

ฉันจะจำการปรับเปลี่ยนคำสั่งเข้ารหัสลับเหล่านี้ไม่ได้ง่ายๆดังนั้นฉันจึงได้คำตอบที่ดีที่สุดและเปลี่ยนเป็นฟังก์ชันใน~/.bashrcไฟล์ของฉัน:


cgrep() {
    # For files that are arrays 10's of thousands of characters print.
    # Use cpgrep to print 30 characters before and after search patttern.
    if [ $# -eq 2 ] ; then
        # Format was 'cgrep "search string" /path/to/filename'
        grep -o -P ".{0,30}$1.{0,30}" "$2"
    else
        # Format was 'cat /path/to/filename | cgrep "search string"
        grep -o -P ".{0,30}$1.{0,30}"
    fi
} # cgrep()

นี่คือสิ่งที่ดูเหมือนว่าเป็นจริง:

$ ll /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

-rw-r--r-- 1 rick rick 25780 Jul  3 19:05 /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

$ cat /tmp/rick/scp.Mf7UdS/Mf7UdS.Source | cgrep "Link to iconic"

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

$ cgrep "Link to iconic" /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

แฟ้มในคำถามเป็นหนึ่งในสาย 25K grepอย่างต่อเนื่องและมันก็เป็นความหวังที่จะพบสิ่งที่คุณกำลังมองหาการใช้ปกติ

สังเกตุทั้งสองวิธีที่แตกต่างกันคุณสามารถเรียกวิธีการcgrepคู่ขนานgrep

มีวิธี "niftier" ในการสร้างฟังก์ชั่นโดยที่ "$ 2" จะถูกส่งเฉพาะเมื่อตั้งค่าซึ่งจะบันทึกรหัส 4 บรรทัด ฉันว่ามันไม่มีประโยชน์เลย ${parm2} $parm2สิ่งที่ชอบ หากฉันพบมันฉันจะแก้ไขฟังก์ชันและคำตอบนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.