Grep के साथ, मैं एक पैटर्न से कैसे मेल कर सकता हूं और इनवर्ट दूसरे पैटर्न से मेल खा सकता है?


11

इसके साथ grep, मैं एक पैटर्न से मेल खाने वाली सभी लाइनों का चयन करना चाहता हूं, और यह दूसरे पैटर्न से मेल नहीं खाता है। मैं एक एकल आह्वान का उपयोग करने में सक्षम होना चाहता हूं grepताकि मैं --after-contextविकल्प (या --before-context, या --context) का उपयोग कर सकूं ।

-vयहां व्यवहार्य नहीं है, क्योंकि यह विकल्प grepका उपयोग करने के लिए मेरे द्वारा पारित सभी पैटर्न को नकारता -eहै।

उदाहरण

मैं निम्नलिखित संदर्भों की एक पंक्ति के साथ, needleमेल खाते हुए रेखाओं की अनदेखी करते हुए, लाइनों की तलाश करना चाहता हूं ignore me

यहाँ मेरी इनपुट फ़ाइल है:

one needle ignore me
two
three
four needle
five

मुझे जो आउटपुट चाहिए वह है:

four needle
five

जैसा कि आप देख सकते हैं, यह भोला समाधान काम नहीं करता है:

$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five

जवाबों:


10

यदि आपके पास ग्नू ग्रीप है, तो आप पर्ल रेगुलर एक्सप्रेशन का उपयोग कर सकते हैं , जिसमें एक निगेटिव कंस्ट्रक्शन है

grep -A1 -P '^(?!.*ignore me).*needle'

यदि आपके पास GNU grep नहीं है, तो आप aw में संदर्भ विकल्पों के पहले / बाद में इसका अनुकरण कर सकते हैं ।

awk -v after=3 -v before=2 '
/needle/ && !/ignore me/ {
    for (i in h) {
        print h[i];
        delete h[i];
    }
    until = NR + after;
}
{
    if (NR <= until) print $0; else h[NR] = $0;
    delete h[NR-before];
}
END {exit !until}
'

8

आप GNU का उपयोग करते दिखाई देते हैं । GNU grep के साथ, आप --perl-regexPCRE को सक्रिय करने के लिए झंडे में पास हो सकते हैं और फिर एक नकारात्मक रूपांतर परख की आपूर्ति कर सकते हैं, उदाहरण के लिए नीचे

grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five

यहाँ ध्यान देने योग्य बात यह है कि (?:(?!STRING).)*जैसा है STRINGवैसा [^CHAR]*ही हैCHAR


@ 1_CR ... सर .. यह कमाल है ..: पी कुछ स्माइलरack
राहुल पाटिल

@RahulPatil। :-), जीएनयू grep अच्छा है।
इरूवर

यह काफी नहीं है कि मुझे क्या चाहिए। मैं चाहता हूं कि यह काम करे कि "मुझे अनदेखा करें" "सुई" से पहले या बाद में है।
फ्लिम

@RahulPatil, धन्यवाद, मैंने इसे नवीनतम संस्करण में तय किया है
iruvar

बहुत उपयोगी। विशेष रूप से संदर्भ के साथ grep के मामले में जहां आप बारीकी से मिलान लाइनों को बाहर करना चाहते हैं, लेकिन पैटर्न के एक निश्चित भाग के बिना। मूल प्रश्न के करीब लेकिन समान नहीं।
गॉथे

2

मैं इसके बजाय awk का उपयोग करने का सुझाव दूंगा क्योंकि यह बहु-पंक्ति IO को बेहतर तरीके से संभालता है। या तो 1) परिणामों को --\nरिकॉर्ड विभाजक के रूप में GNU awk पर पाइप करें , या 2) aw में सभी मिलान करें।

विकल्प 1

<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'

आउटपुट:

four needle                                                                                  
five
--

ध्यान दें, यह विकल्प केवल पहली पंक्ति की तुलना में पूरे रिकॉर्ड को खोजता है ignore me, सेट करता है FS=1और मैच करता है $1

विकल्प 2

<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1

वहाँ ignore meफ़ाइल में कई है, तो काम नहीं करता है
राहुल पाटिल

@RahulPatil: क्या आप अपने प्रश्न को अधिक विस्तार या जोड़ सकते हैं? मुझे समझ नहीं आ रहा है कि आप क्या पूछ रहे हैं।
थॉर

@ इस इनपुट फ़ाइल पेस्ट के
राहुल पाटिल

@RahulPatil: मैं देख रहा हूं कि अब आपका क्या मतलब है, विकल्प 1 मानता है कि --\nप्रत्येक मिलान किए गए समूह के बीच एक सीमांकक है, जो कि समूह एक दूसरे से सटे हुए नहीं हैं। आसन्न समूहों को कैसे संभाला जाना चाहिए यह कार्य-विशिष्ट है, इसलिए यह आवश्यक रूप से गलत नहीं है। विकल्प 2 विभाजक पर निर्भर नहीं करता है और प्रभावित नहीं होता है।
थॉर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.