कई और पैटर्न के साथ grep कैसे चलाएं?


86

मैं कई पैटर्न को अंतर्निहित और पैटर्न के बीच, अर्थात एक क्रम में कई greps चलाने के बराबर करना चाहता हूं:

grep pattern1 | grep pattern2 | ...

तो कैसे इसे कुछ करने के लिए परिवर्तित करने के लिए?

grep pattern1 & pattern2 & pattern3

मैं सिंगल grep का उपयोग करना चाहूंगा क्योंकि मैं गतिशील रूप से तर्क का निर्माण कर रहा हूं, इसलिए सब कुछ एक स्ट्रिंग में फिट होना है। फ़िल्टर का उपयोग करना सिस्टम फीचर है, grep नहीं, इसलिए यह इसके लिए तर्क नहीं है।


इस प्रश्न को भ्रमित न करें:

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

यह एक OR मल्टी पैटर्न मैच है।



जवाबों:


78

agrep इस सिंटैक्स के साथ कर सकते हैं:

agrep 'pattern1;pattern2'

जीएनयू के साथ grep, जब पीसीआरई समर्थन के साथ बनाया जाता है, तो आप कर सकते हैं:

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

Ast केgrep साथ :

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

( दोनों के और बिल्कुल मेल खाने वाले स्ट्रिंग्स के .*रूप में जोड़ना , कभी भी मेल नहीं खाएगा क्योंकि ऐसा कोई स्ट्रिंग नहीं है जो एक ही समय और दोनों में हो सकता है )।<x>&<y><x><y> a&bab

यदि पैटर्न ओवरलैप नहीं करते हैं, तो आप भी कर सकते हैं:

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

सबसे अच्छा पोर्टेबल तरीका शायद awkपहले से ही उल्लेख किया गया है:

awk '/pattern1/ && /pattern2/'

के साथ sed:

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

कृपया सावधान रहें कि उन सभी के पास अलग-अलग नियमित अभिव्यक्ति वाक्यविन्यास होंगे।


1
agrepवाक्य रचना मेरे लिए काम नहीं कर रहा है ... कौन सा संस्करण में पेश किया गया था?
रमन

1992 से @ रामन 2.04 पहले से ही था। मुझे विश्वास है कि यह शुरू से वहाँ नहीं था। Newer (1992 के बाद) के संस्करणों को झलक / वेबलॉगिंग केagrep साथ शामिल किया जा सकता है । संभवतः आपके पास एक अलग कार्यान्वयन है। हालांकि, मुझे एक्स-रे संस्करण के लिए एक गलती थी, संवर्धित रीजैक्स के लिए विकल्प है , नहीं । -X-A
स्टीफन चेज़लस

@ स्टीफेनचैलेजस धन्यवाद, agrepफेडोरा 23 पर मेरे पास 0.8.0 है। यह agrepआपके द्वारा संदर्भित संदर्भ से अलग प्रतीत होता है ।
रमन

1
@ रामन, तुम्हारी आवाज़ TREagrep जैसी है ।
स्टीफन चेजलस

2
@ तीची, या सिर्फawk '/p1/ && /p2/ {n++}; END {print 0+n}'
स्टीफन चेज़लस

19

आपने grep संस्करण निर्दिष्ट नहीं किया, यह महत्वपूर्ण है। कुछ regexp इंजन कई मेल खाने और 'और' का उपयोग करने की अनुमति देते हैं, लेकिन यह गैर-मानक और गैर-पोर्टेबल सुविधा है। लेकिन, कम से कम GNU grep इसका समर्थन नहीं करता है।

OTOH आप बस sed, awk, perl, आदि के साथ grep को बदल सकते हैं (वजन बढ़ने के क्रम में सूचीबद्ध)। Awk के साथ, कमांड दिखेगी

awk '/ regexp1 / && / regexp2 / && / regexp3 / {Print; } '

और इसे आसान तरीके से कमांड लाइन में निर्दिष्ट करने के लिए निर्माण किया जा सकता है।


3
बस याद रखें कि awkERE का उपयोग करता है, जैसे grep -Eकि BRE के सादे grepउपयोग के विपरीत, के बराबर ।
jw013

3
awk's regexes को EREs कहा जाता है , लेकिन वास्तव में वे थोड़ा बेवकूफ हैं। यहाँ शायद किसी के लिए और अधिक विवरण हैं: wiki.alpinelinux.org/wiki/Rexx
dubiousjim

शुक्रिया, grep 2.7.3 (openSUSE)। मैंने आपको उकसाया, लेकिन मैं थोड़ी देर के लिए प्रश्न को खुला रखूंगा, शायद जीआरईपी के लिए कुछ चाल है (यह नहीं कि मुझे नापसंद है awk- बस और अधिक जानना बेहतर है)।
ग्रीनल्डमैन

2
डिफ़ॉल्ट कार्रवाई मिलान रेखा को प्रिंट करने के लिए होती है इसलिए { print; }भाग वास्तव में आवश्यक या उपयोगी नहीं है।
त्रिपली २०'१

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==1में gawk

ये फ़ंक्शन STDIN की पंक्तियों को प्रिंट करते हैं जिनमें एक स्ट्रिंग के रूप में निर्दिष्ट प्रत्येक स्ट्रिंग एक विकल्प के रूप में होता है। gaजीआरपी सभी के लिए खड़ा है और 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

यह सबसे तेज ग्रेपिंग टूल में से एक है, क्योंकि यह रस्ट के रेगेक्स इंजन के शीर्ष पर बनाया गया है , जो खोज को बहुत तेज़ बनाने के लिए परिमित ऑटोमेटा, SIMD और आक्रामक शाब्दिक अनुकूलन का उपयोग करता है।

GH-875 पर संबंधित सुविधा अनुरोध भी देखें ।


1

यहाँ मेरा लेना है, और यह कई लाइनों में शब्दों के लिए काम करता है:

का प्रयोग करें find . -type fके रूप में कई द्वारा पीछा किया
-exec grep -q 'first_word' {} \;
और साथ अंतिम कीवर्ड
-exec grep -l 'nth_word' {} \;

-q
-lमैचों के साथ शांत / मूक शो फ़ाइलें

निम्नलिखित शब्द 'खरगोश' और 'छेद' वाले फ़ाइल नाम की सूची में हैं:
find . -type f -exec grep -q 'rabbit' {} \; -exec grep -l 'hole' {} \;


-2

सभी शब्दों (या पैटर्न) को खोजने के लिए, आप फॉर लूप में grep चला सकते हैं । यहाँ मुख्य लाभ, रेगेक्स की सूची से खोज रहा है ।

एक वास्तविक उदाहरण के साथ मेरा उत्तर संपादित करें :

# 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

CAA

# ./search_all_regex_and_error_if_missing.sh

आआआआआआआआआ आआआ

^ a + $ फ़ाइल में मिली।

bbbbbbbbb bbbb

फ़ाइल में ^ b + $ मिला।

hhhhhhhhhh

फ़ाइल में ^ h + $ मिला।

त्रुटि: ^ d + $ फ़ाइल में नहीं मिली। बाहर निकल रहा है!


1
आपका तर्क दोषपूर्ण है - मैंने ALLऑपरेटर से पूछा , आपका कोड ORऑपरेटर के रूप में काम करता है , नहीं AND। और btw। उसके लिए ( OR) सवाल में बहुत आसान समाधान दिया गया है।
ग्रीनल्डमैन

@greenoldman तर्क सरल है: सूची में सभी शब्दों / पैटर्नों पर लूप के लिए, और यदि यह फ़ाइल में पाया जाता है - तो इसे प्रिंट करेगा। यदि आपको शब्द नहीं मिला तो कार्रवाई की आवश्यकता नहीं है, इसलिए अभी और निकालें।
नोआम मानोस

1
मैं आपके तर्क के साथ-साथ मेरे प्रश्न को भी समझता हूं - मैं ANDऑपरेटर के बारे में पूछ रहा था , जिसका अर्थ है कि फ़ाइल केवल एक सकारात्मक हिट है यदि यह पैटर्न ए और पैटर्न बी और पैटर्न सी से मेल खाती है और ... ANDआपके मामले में फ़ाइल सकारात्मक हिट है यदि यह मेल खाता है पैटर्न A या पैटर्न B या ... क्या आपको अब अंतर दिखाई देता है?
ग्रीनोल्डमैन

@greenoldman को यकीन नहीं है कि आपको क्यों लगता है कि यह लूप सभी पैटर्नों के लिए जाँच और शर्त नहीं करता है? इसलिए मैंने अपना उत्तर एक वास्तविक उदाहरण के साथ संपादित किया है: यह सूची के सभी regex के लिए फ़ाइल में खोज करेगा, और पहले वाले पर जो गायब है - त्रुटि के साथ बाहर निकल जाएगा।
नोम मानोस

आपके पास अपनी आंखों के सामने यह अधिकार है, आपके पास पहले मैच के बाद ही सकारात्मक मैच होगा। आपके पास सभी परिणाम "एकत्रित" होने चाहिए और ANDउन पर गणना करनी चाहिए । फिर आपको कई फ़ाइलों पर चलने के लिए स्क्रिप्ट को फिर से लिखना चाहिए - तब शायद आपको पता चले कि प्रश्न पहले से ही उत्तर दिया गया है और आपका प्रयास टेबल पर कुछ भी नहीं लाता है, क्षमा करें।
ग्रीनोल्डमैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.