จำกัด บริบทของ grep ไม่เกินอักขระ N บรรทัด


31

ฉันต้อง grep ผ่านไฟล์ JSON บางไฟล์ที่ความยาวบรรทัดเกินสองสามพันตัวอักษร ฉันจะ จำกัด grep เพื่อแสดงบริบทได้สูงสุด N ตัวอักษรไปทางซ้ายและขวาของการจับคู่อย่างไร เครื่องมืออื่นที่ไม่ใช่ grep ก็ใช้ได้เช่นกันตราบใดที่มันมีอยู่ในแพ็คเกจ Linux ทั่วไป

นี่จะเป็นตัวอย่างเอาต์พุตสำหรับสวิตช์ grep จินตภาพ inary :

$ grep -r foo *
hello.txt: Once upon a time a big foo came out of the woods.

$ grep -Ф 10 -r foo *
hello.txt: ime a big foo came of t



3
ไม่ซ้ำกัน นี่คือประมาณ±อักขระ แต่ทางเลือกที่คุณแนะนำคือประมาณ±บรรทัด (อ้างอิงของคุณไปStackOverflowเป็นสิ่งที่ดีแม้ว่า.)
roaima

คำตอบ:


22

ด้วย GNU grep:

N=10; grep -roP ".{0,$N}foo.{0,$N}" .

คำอธิบาย:

  • -o => พิมพ์เฉพาะสิ่งที่คุณจับคู่
  • -P => ใช้นิพจน์ปกติสไตล์ Perl
  • regex บอกว่าจับคู่ 0 กับ$Nตัวอักษรตามด้วยfooตามด้วย 0 ถึง$Nตัวละคร

หากคุณไม่มี GNU grep:

find . -type f -exec \
    perl -nle '
        BEGIN{$N=10}
        print if s/^.*?(.{0,$N}foo.{0,$N}).*?$/$ARGV:$1/
    ' {} \;

คำอธิบาย:

เนื่องจากเราไม่สามารถพึ่งพาgrepGNU ได้อีกต่อไปgrepเราจึงใช้findการค้นหาไฟล์แบบเรียกซ้ำ (การ-rกระทำของ GNU grep) สำหรับแต่ละไฟล์ที่พบเราดำเนินการตัวอย่างโค้ด Perl

สวิตช์ Perl:

  • -n อ่านไฟล์ทีละบรรทัด
  • -l นำขึ้นบรรทัดใหม่ที่ท้ายบรรทัดแต่ละบรรทัดแล้วนำกลับมาใหม่เมื่อพิมพ์
  • -e ถือเป็นสตริงต่อไปนี้เป็นรหัส

Perl grepข้อมูลโค้ดจะทำหลักเป็นสิ่งเดียวกับ มันเริ่มต้นด้วยการตั้งค่าตัวแปร$Nตามจำนวนตัวอักษรบริบทที่คุณต้องการ BEGIN{}วิธีนี้จะถูกดำเนินการเพียงครั้งเดียวในช่วงเริ่มต้นของการดำเนินการไม่ได้ครั้งเดียวสำหรับสายในไฟล์ทุก

คำสั่งที่ดำเนินการสำหรับแต่ละบรรทัดคือการพิมพ์บรรทัดหากการทดแทน regex ทำงาน

Regex:

  • ตรงกับสิ่งเก่า ๆ อย่างเกียจคร้าน1ที่จุดเริ่มต้นของบรรทัด ( ^.*?) ตามด้วย.{0,$N}ในgrepกรณีตามด้วยfooตามด้วยอีกอันหนึ่ง.{0,$N}และในที่สุดก็จับคู่สิ่งเก่า ๆ อย่างเกียจคร้านจนถึงจุดสิ้นสุดของบรรทัด ( .*?$)
  • $ARGV:$1เราทดแทนนี้กับ $ARGVเป็นตัวแปรเวทมนต์ที่เก็บชื่อไฟล์ปัจจุบันที่กำลังอ่าน $1เป็นสิ่งที่ parens จับคู่: บริบทในกรณีนี้
  • การจับคู่แบบขี้เกียจที่ปลายทั้งสองข้างนั้นเป็นเพราะการจับคู่โลภจะกินตัวละครทั้งหมดก่อนfooโดยไม่ล้มเหลวในการจับคู่ (เนื่องจาก.{0,$N}ได้รับอนุญาตให้จับคู่เป็นศูนย์ครั้ง)

1 นั่นคือไม่ต้องการจับคู่สิ่งใดเลยนอกจากจะทำให้การจับคู่โดยรวมล้มเหลว กล่าวโดยย่อให้จับคู่อักขระน้อยที่สุด


ดีมากขอบคุณ สิ่งนี้มีข้อเสียเปรียบในการเน้นผลลัพธ์ทั้งหมดไม่ใช่แค่ค้นหาข้อความ แต่สามารถแก้ไขได้ด้วยการต่อท้าย| grep fooจนจบ (แต่จะทำให้ชื่อไฟล์ที่ไฮไลต์อยู่ในกระบวนการหายไป)
dotancohen

1
@dotancohen ผมคิดว่าคุณไม่สามารถชนะพวกเขาทั้งหมด :)
โจเซฟอาร์

w / GNU grepคุณสามารถระบุการจับคู่สี / แอปพลิเคชันตามค่าสถานะที่ใช้ผ่านตัวแปรสภาพแวดล้อม ดังนั้นบางทีคุณอาจชนะได้ทั้งหมด(ไม่มีสัญญา - ไม่แน่ใจว่ามันจะใช้ได้ในกรณีนี้)แต่ฉันไม่เห็นความเกี่ยวข้องที่นี่ ... ต่อไป ... เล่นต่อไป
mikeserv

คำตอบที่ดี แค่ทราบว่าการใช้zshฉันไม่สามารถทำให้มันทำงานผ่าน N = 10 ได้ดังตัวอย่าง อย่างไรก็ตามมันจะทำงานถ้าฉันexport N=10ก่อนที่จะใช้คำสั่ง แนวคิดใดที่จะปรับตัวอย่างเพื่อทำงานกับ zsh?
Gabe Kopley

หรือperl -lne 'print "$ARGV: $_" for /.{0,10}foo.{0,10}/g'
Stéphane Chazelas

19

ลองใช้อันนี้:

grep -r -E -o ".{0,10}wantedText.{0,10}" *

-Eบอกว่าคุณต้องการใช้ Extended Regex

-oบอกว่าคุณต้องการพิมพ์เฉพาะการแข่งขัน

-r grep กำลังค้นหาผลลัพธ์ซ้ำในโฟลเดอร์

ทั่วไป REGEX:

{0,10}บอกจำนวนอักขระที่คุณต้องการพิมพ์

. แสดงถึงตัวละครโดยพลการ (ตัวละครนั้นไม่สำคัญที่นี่เพียงแค่จำนวนของพวกเขา)

แก้ไข:โอ้ฉันเข้าใจแล้วว่าโจเซฟแนะนำวิธีแก้ปัญหาแบบเดียวกับฉัน: D


ขอขอบคุณ. แม้ว่าจะเป็นวิธีการแก้ปัญหาเดียวกันเป็นหลัก แต่ก็เป็นแรงบันดาลใจอย่างมั่นใจว่านี่เป็นวิธีการที่ดีที่สุดเมื่อคนสองคนแนะนำด้วยตนเอง
dotancohen

ยินดีต้อนรับชุมชน Unix เพียงแค่ต้องร่วมมือนั่นคือสิ่งที่เรา :-)
Eenoku

2
แม้ว่าพวกเขาจะคล้ายกันคำตอบที่ได้รับการยอมรับไม่ได้ผลสำหรับฉัน (ยังคงผลิตสายยาว) แต่สิ่งนี้ก็ทำ เคล็ดลับที่มี N = 10 ไม่สามารถใช้ได้กับเชลล์ bash
meesern

ในcygwin -Eเร็วกว่า-Pมาก
Bob Stein

2

นำมาจาก: http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/ และ https: // stackoverflow ดอทคอม / a / 39029954/1150462

วิธีที่แนะนำ".{0,10}<original pattern>.{0,10}"นั้นดีมากยกเว้นสีที่ไฮไลต์มักจะเลอะ ฉันได้สร้างสคริปต์ที่มีเอาต์พุตคล้ายกัน แต่สียังคงอยู่:

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 | grep --color=none -oE ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

สมมติว่าสคริปต์จะถูกบันทึกเป็นgreplแล้วgrepl pattern file_with_long_linesควรแสดงเส้นจับคู่ แต่มีเพียง 10 ตัวอักษรรอบการจับคู่สาย


0

การวางท่อ stdout cutด้วย-bธง; คุณสามารถสั่งให้เอาต์พุตของ grep ไปที่ไบต์ 1 ถึง 400 ต่อบรรทัดเท่านั้น

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