grep "फू" के उदाहरणों को खोजने के लिए जहां "बार" 10 लाइनों में प्रकट नहीं होता है


10

मान लीजिए कि मैं सभी सीपीपी फाइलों के लिए एक संपूर्ण पेड़ खोजना चाहता हूं जहां "फू" होता है। मैं शायद कर सकता हूं:

find . -name "*.cpp" | xargs grep "Foo"

अब मान लीजिए कि मैं केवल उन उदाहरणों को सूचीबद्ध करना चाहता हूं जहां कुछ अन्य स्ट्रिंग कहते हैं, "बार" पिछले परिणाम की 3 पंक्तियों के भीतर नहीं होता है।

इसलिए दो फाइलें दी गई हैं:

a.cpp

1 Foo
2 qwerty
3 qwerty

b.cpp

1 Foo
2 Bar
3 qwerty

मैं एक साधारण खोज का निर्माण करना चाहूंगा, जहां a.cpp से "फू" पाया जाता है, लेकिन b.cpp से "फू" नहीं है।

क्या इसे काफी सरल तरीके से पूरा करने का एक तरीका है?


शायद समाधान विकल्प grep -A और / या grep -B और / या grep -C में हो सकता है। मैं कोशिश कर रहा हूँ, लेकिन बिना किसी
कोलाहल के

@ maurelio79: मेरा वर्तमान सिद्धांत यह है। संदर्भ के लिए -10 का उपयोग करके "फू" के लिए ग्रीप। पाइप कि grep -v बार। पाइप जो फ़ाइल नाम और लाइन नंबर प्राप्त करने के लिए सेड करने के लिए। उस लाइन को प्रिंट करने के लिए पाइप (कुछ (?)।
जॉन डिब्लिंग

जवाबों:


17

के साथ pcregrep:

pcregrep --include='\.cpp$' -rnM 'Foo(?!(?:.*\n){0,2}.*Bar)' .

कुंजी उस -Mविकल्प में है जो अद्वितीय है pcregrepऔर इसका उपयोग कई लाइनों से मेल खाने के लिए किया जाता है ( pcregrepजब आरई यह मांग करता है तो इनपुट फ़ाइल से अधिक डेटा खींचता है)।

(?!...)पर्ल / पीसीआरई नेगेटिव लुक-फॉरवर्ड आरई ऑपरेटर है। जब तक Foo(?!...)मेल नहीं खाता तब तक क्या होता है।Foo...

...होना (?:.*\n){0,2}.*Bar( .न्यूलाइन कैरेक्टर का मेल न होना), जो कि 0 से 2 लाइनों के बाद वाली लाइन है Bar


+1: बहुत बढ़िया। बहुत बहुत धन्यवाद; मुझे यकीन है कि सही रेगेक्स का पता लगाना आसान नहीं था। मैं आपके प्रयासों की बहुत सराहना करता हूं। यह ठीक वैसा ही काम कर रहा है जैसा मैं चाहता था।
जॉन डिबलिंग

2
यदि आप जवाब देना चाहते हैं तो साइड सवाल करें। आपको कैसे पता चला pcregrep? मैंने इसके बारे में पहले कभी नहीं सुना।
जॉन डिब्लिंग

@ जॉनडब्लिंग, मुझे व्यक्तिगत रूप से हाल ही में यूनिक्स में पता चला है । यह आरई विशेष रूप से जटिल नहीं है, खासकर जब आप (?!...)नकारात्मक रूप-आगे perlआरई ऑपरेटर से परिचित हैं ।
स्टीफन चेजालस

9

कोई बात नहीं, बस का उपयोग pcregrepके रूप में सुझाव दिया @StephaneChazelas द्वारा।


यह काम करना चाहिए:

$ find . -name "*.cpp" | 
    while IFS= read -r file; do 
      grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; 
    done 

-Aमिलान लाइनों और एन निम्नलिखित लाइनों के उत्पादन के लिए grep के स्विच का उपयोग करने का विचार है । आप तब परिणाम को पास करते हैं grep Barऔर यदि वह मेल नहीं खाता (बाहर निकलें> 0), तो आप फ़ाइल का नाम गूँजते हैं।

यदि आप जानते हैं कि आपके पास फ़ाइल नाम हैं (कोई रिक्त स्थान, नई लाइनें या अन्य अजीब अक्षर नहीं), तो आप इसे सरल कर सकते हैं:

$ for file in $(find . -name "*.cpp"); do 
   grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; 
  done 

उदाहरण के लिए:

terdon@oregano foo $ cat a.cpp 
1 Foo
2 qwerty
3 qwerty
terdon@oregano foo $ cat b.cpp 
1 Foo
2 Bar
3 qwerty
terdon@oregano foo $ cat c.cpp 
1 Foo
2 qwerty
3 qwerty
4 qwerty
5. Bar
terdon@oregano foo $ for file in $(find . -name "*.cpp"); do grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; done 
./c.cpp
./a.cpp

ध्यान दें कि c.cppयुक्त होने के बावजूद वापस आ गया है Barक्योंकि रेखा Bar3 रेखाओं से अधिक है Foo। आप उस मान की संख्या को नियंत्रित करते हैं जिसे आप खोज करना चाहते हैं -A:

$ for file in $(find . -name "*.cpp"); do 
   grep -A 10 Foo "$file" | grep -q Bar || echo "$file"; 
  done 
./a.cpp

यहाँ एक छोटा है (आप का उपयोग करते हुए bash):

$ shopt -s globstar 
$ for file in **/*cpp; do 
    grep -A 10 Foo "$file" | grep -q Bar || echo "$file"; 
  done

जरूरी

जैसा कि स्टीफन चेज़ेलस ने टिप्पणियों में बताया है, उपरोक्त समाधान उन फ़ाइलों को भी प्रिंट करेंगे जिनमें बिल्कुल नहीं हैं Foo। इससे बचा जाता है:

for file in **/*cpp; do 
  grep -qm 1 Foo "$file" && 
  (grep -A 3 Foo "$file" | grep -q Bar || echo "$file"); 
done

+1 साफ-सुथरा। जितना मैं उम्मीद कर रहा था उससे थोड़ा अधिक जटिल, लेकिन बुरा बिल्कुल नहीं।
जॉन डिब्लिंग

यह मानता है कि "फू" केवल एक बार होता है। इसमें उन फ़ाइलों की रिपोर्ट भी होगी, जिनमें शामिल नहीं हैं Foo। आपके पास गुम उद्धरण हैं।
स्टीफन चेज़लस

@StephaneChazelas धन्यवाद, उद्धरण निश्चित। आप फ़ाइलों की रिपोर्टिंग के बारे में बिल्कुल सही हैं Fooऔर मैंने इसे ठीक कर दिया है, लेकिन मैं आपके उदाहरण के कई उदाहरणों के बारे में नहीं देखता हूं Foo। इससे उन्हें सही तरीके से निपटना चाहिए।
terdon

@JohnDibling अपडेट देखें।
terdon

1
यह "फू" की 100 पंक्तियों वाली फ़ाइल की रिपोर्ट नहीं करेगा, जिसके बाद "बार" होगा।
स्टीफन चेजलस

0

अनकहा, मैं अपने फोन पर हूं:

find . -name "*.cpp" | xargs awk '/foo/{t=$0;c=10}/bar/{c=0;t=""}c{c--}t&&!c{print t;t=""}END&&t{print t}' 

ऐसा कुछ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.