วิธีการเรียกใช้ grep ที่มีหลายรูปแบบและ?


86

ฉันต้องการได้รับการจับคู่หลายรูปแบบโดยนัยและระหว่างรูปแบบเช่นเทียบเท่ากับการรัน greps หลายตัวตามลำดับ:

grep pattern1 | grep pattern2 | ...

ดังนั้นวิธีการแปลงเป็นบางอย่างเช่น?

grep pattern1 & pattern2 & pattern3

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


อย่าสับสนคำถามนี้ด้วย:

grep "pattern1\|pattern2\|..."

นี่คือการจับคู่รูปแบบOR หรือหลายแบบ



คำตอบ:


78

agrep สามารถทำได้ด้วยไวยากรณ์นี้:

agrep 'pattern1;pattern2'

ด้วย GNU grepเมื่อสร้างด้วยการรองรับ PCRE คุณสามารถทำได้:

grep -P '^(?=.*pattern1)(?=.*pattern2)'

ด้วยastgrep :

grep -X '.*pattern1.*&.*pattern2.*'

(เพิ่ม.*ในฐานะที่<x>&<y>ตรงกับสายที่ตรงกับทั้งสอง<x>และ<y> ตรง , a&bจะไม่ตรงกับความเป็นไม่มีสตริงดังกล่าวที่สามารถเป็นทั้งสองaและbในเวลาเดียวกัน)

หากรูปแบบไม่ทับซ้อนกันคุณอาจทำได้:

grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'

วิธีพกพาที่ดีที่สุดน่าจะawkเป็นที่กล่าวถึงแล้ว:

awk '/pattern1/ && /pattern2/'

ด้วยsed:

sed -e '/pattern1/!d' -e '/pattern2/!d'

โปรดระวังว่าสิ่งเหล่านั้นจะมีไวยากรณ์การแสดงออกปกติที่แตกต่างกัน


1
agrepไวยากรณ์ไม่ทำงานสำหรับฉัน ... รุ่นที่มันเป็นที่รู้จักใน?
รามัน

@Raman 2.04 จากปี 1992มีแล้ว ฉันไม่มีเหตุผลที่จะเชื่อว่ามันไม่ได้มีตั้งแต่เริ่มต้น บทความที่ใหม่กว่า (หลัง 1992) รุ่นที่agrepสามารถพบได้พร้อมกับเหลือบ / WebGlimpse อาจเป็นไปได้ว่าคุณมีการนำไปใช้ที่แตกต่างกัน ฉันมีความผิดพลาดสำหรับรุ่น AST-grep แม้ว่าตัวเลือกสำหรับregexps เติมเป็นไม่ได้-X -A
Stéphane Chazelas

@ StéphaneChazelasขอบคุณฉันมีagrep0.8.0 ใน Fedora 23 สิ่งนี้ดูเหมือนจะแตกต่างagrepจากที่คุณอ้างอิง
Raman

1
@Raman, คุณเสียงเหมือนTRE agrep
Stéphane Chazelas

2
@Techiee หรือเพียงแค่awk '/p1/ && /p2/ {n++}; END {print 0+n}'
Stéphane Chazelas

19

คุณไม่ได้ระบุเวอร์ชัน grep นี่เป็นสิ่งสำคัญ เอ็นจิ้น regexp บางตัวอนุญาตการจับคู่หลาย ๆ อันด้วยและใช้ '&' แต่นี่ไม่ใช่คุณสมบัติมาตรฐานและไม่พกพา แต่อย่างน้อย GNU grep ไม่สนับสนุนสิ่งนี้

OTOH คุณสามารถแทนที่ grep ด้วย sed, awk, perl และอื่น ๆ (ตามลำดับน้ำหนักที่เพิ่มขึ้น) ด้วย awk คำสั่งจะมีลักษณะ

awk '/ regexp1 / && / regexp2 / && / regexp3 / {พิมพ์; }'

และสามารถสร้างขึ้นเพื่อระบุในบรรทัดคำสั่งในวิธีที่ง่าย


3
เพียงจำไว้ว่าawkใช้ของ ERE เช่นเทียบเท่าgrep -Eเมื่อเทียบกับของ BRE ที่grepใช้ธรรมดา
jw013

3
awkregexes ของถูกเรียกว่า EREs แต่ในความเป็นจริงพวกเขามีนิสัยแปลก ๆ นี่อาจเป็นรายละเอียดมากกว่าที่ทุกคนใส่ใจ: wiki.alpinelinux.org/wiki/Regex
dubiousjim

ขอบคุณ grep 2.7.3 (openSUSE) ฉัน upvoted คุณ แต่ฉันจะทำให้คำถามเปิดในขณะที่อาจจะมีเคล็ดลับบางอย่างสำหรับ grep (ไม่ใช่ว่าผมไม่ชอบawk- เพียงแค่รู้เพิ่มเติมจะดีกว่า)
greenoldman

2
การกระทำเริ่มต้นคือการพิมพ์บรรทัดการจับคู่ดังนั้น{ print; }ส่วนที่ไม่จำเป็นจริงๆหรือมีประโยชน์ที่นี่
tripleee

7

หากpatternsมีหนึ่งรูปแบบต่อบรรทัดคุณสามารถทำสิ่งนี้:

awk 'NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1' patterns -

หรือสิ่งนี้จับคู่สตริงย่อยแทนนิพจน์ทั่วไป:

awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns -

หากต้องการพิมพ์ทั้งหมดแทนสายของการป้อนข้อมูลในกรณีที่ไม่patternsว่างเปล่าแทนที่NR==FNRด้วยFILENAME==ARGV[1]หรือในARGIND==1gawk

ฟังก์ชั่นเหล่านี้พิมพ์บรรทัดของ STDIN ซึ่งมีแต่ละสตริงที่ระบุเป็นอาร์กิวเมนต์เป็นสตริงย่อย gaย่อมาจาก grep all และgaiไม่สนใจขนาดตัวพิมพ์

ga(){ awk 'FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1' <(printf %s\\n "$@") -; }
gai(){ awk 'FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1' <(printf %s\\n "$@") -; }

7

นี่ไม่ใช่ทางออกที่ดีมาก แต่แสดงให้เห็นถึง "เคล็ดลับ" ที่ค่อนข้างเย็น

function chained-grep {
    local pattern="$1"
    if [[ -z "$pattern" ]]; then
        cat
        return
    fi    

    shift
    grep -- "$pattern" | chained-grep "$@"
}

cat something | chained-grep all patterns must match order but matter dont

1
ใช้อย่างใดอย่างหนึ่งchained-grep()หรือfunction chained-grepไม่function chained-grep(): unix.stackexchange.com/questions/73750/…
nisetama

3

git grep

นี่คือไวยากรณ์โดยใช้git grepการรวมหลายรูปแบบโดยใช้นิพจน์บูลีน :

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3

คำสั่งดังกล่าวจะพิมพ์บรรทัดที่ตรงกับรูปแบบทั้งหมดในครั้งเดียว

--no-index ค้นหาไฟล์ในไดเรกทอรีปัจจุบันที่ไม่ได้รับการจัดการโดย Git

ตรวจสอบman git-grepความช่วยเหลือ

ดูสิ่งนี้ด้วย:

สำหรับหรือการดำเนินการโปรดดูที่:


1

ripgrep

นี่คือตัวอย่างการใช้rg:

rg -N '(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)' file.txt

เป็นหนึ่งในเครื่องมือ grepping ที่เร็วที่สุดเนื่องจากมันถูกสร้างขึ้นจากเครื่องมือ regex ของ Rustซึ่งใช้ออโต้ไฟน์ จำกัด , SIMD และการเพิ่มประสิทธิภาพตามตัวอักษรที่ก้าวร้าวเพื่อให้การค้นหารวดเร็วมาก

ดูคำขอคุณสมบัติยังในGH-875


1

นี่คือสิ่งที่ฉันใช้และใช้ได้ผลกับคำในหลายบรรทัด:

ใช้find . -type fตามด้วย
-exec grep -q 'first_word' {} \;
คำหลักจำนวนมาก และสุดท้ายด้วย
-exec grep -l 'nth_word' {} \;

-q
-lไฟล์แสดงเงียบ / เงียบ พร้อมการจับคู่

ส่งคืนรายการชื่อไฟล์ต่อไปนี้ที่มีคำว่า 'rabbit' และ 'hole' ในคำเหล่านั้น:
find . -type f -exec grep -q 'rabbit' {} \; -exec grep -l 'hole' {} \;


-2

ในการค้นหาคำทั้งหมด (หรือรูปแบบ) คุณสามารถรัน grep ใน FOR วนได้ ประโยชน์หลักที่นี่คือการค้นหาจากรายการ regexs

แก้ไขคำตอบของฉันด้วยตัวอย่างจริง:

# search_all_regex_and_error_if_missing.sh 

find_list="\
^a+$ \
^b+$ \
^h+$ \
^d+$ \
"

for item in $find_list; do
   if grep -E "$item" file_to_search_within.txt 
   then
       echo "$item found in file."
   else
       echo "Error: $item not found in file. Exiting!"
       exit 1
   fi
done

ตอนนี้ให้เรียกใช้กับไฟล์นี้:

hhhhhhhhhh

aaaaaaa

bbbbbbbbb

ababbabaabbaaa

ccccccc

dsfsdf

bbbb

cccdd

AA

CAA

# ./search_all_regex_and_error_if_missing.sh

aaaaaaa aa

พบ a + $ ในไฟล์

bbbbbbbbb bbbb

พบ ^ b + $ ในไฟล์

hhhhhhhhhh

พบ ^ h + $ ในไฟล์

ข้อผิดพลาด: ไม่พบ ^ d + $ ในไฟล์ การออก!


1
ตรรกะของคุณเป็นความผิดพลาด - ฉันขอให้ALLผู้ประกอบการรหัสของคุณทำงานเป็นผู้ประกอบการไม่ได้OR ANDและ btw สำหรับ ( OR) นั้นเป็นคำตอบที่ง่ายกว่ามากในคำถาม
greenoldman

@greenoldman ลอจิกนั้นง่าย: for for จะวนซ้ำทุกคำ / รูปแบบในรายการและหากพบในไฟล์ - จะพิมพ์ออกมา ดังนั้นเพียงลบสิ่งอื่นถ้าคุณไม่ต้องการดำเนินการในกรณีที่ไม่พบคำว่า
Noam Manos

1
ฉันเข้าใจตรรกะของคุณเช่นเดียวกับคำถามของฉัน - ฉันถูกถามเกี่ยวกับANDโอเปอเรเตอร์หมายความว่าไฟล์นี้เป็นเพียงการตีบวกถ้ามันตรงกับรูปแบบ A และรูปแบบ B และรูปแบบ C และ ... ANDในกรณีที่คุณเป็นไฟล์ รูปแบบ A หรือรูปแบบ B หรือ ... คุณเห็นความแตกต่างตอนนี้หรือไม่
greenoldman

@greenoldman ไม่แน่ใจว่าทำไมคุณคิดว่าการวนซ้ำนี้ไม่ได้ตรวจสอบและเงื่อนไขสำหรับรูปแบบทั้งหมดหรือไม่ ดังนั้นฉันจึงได้แก้ไขคำตอบของฉันด้วยตัวอย่างจริง: มันจะค้นหาไฟล์สำหรับรายการ regex ทั้งหมดและในรายการแรกที่หายไป - จะออกโดยมีข้อผิดพลาด
Noam Manos

คุณมีมันอยู่ตรงหน้าดวงตาของคุณคุณมีการแข่งขันในเชิงบวกเพียงหลังจากการแข่งขันครั้งแรกจะดำเนินการ คุณควรมี "รวบรวม" ผลลัพธ์ทั้งหมดและคำนวณANDกับพวกเขา จากนั้นคุณควรเขียนสคริปต์เพื่อให้ทำงานกับไฟล์หลาย ๆ ไฟล์ - บางทีคุณอาจรู้ว่าคำถามนั้นได้รับคำตอบแล้วและความพยายามของคุณไม่ได้นำสิ่งใดมาลงในตารางขออภัย
greenoldman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.