दो शब्दों में से एक के साथ एक लाइन के लिए खोज करने के लिए grep का उपयोग कैसे करें लेकिन दोनों नहीं?


11

मैं एक पाठ फ़ाइल में 'word1' XOR 'word2' के साथ लाइनों की खोज करना चाहता हूं। तो यह वर्ड 1, वर्ड 2 के साथ लाइनों का उत्पादन करना चाहिए, लेकिन इन दोनों शब्दों के साथ लाइनें नहीं। मैं XOR का उपयोग करना चाहता था, लेकिन मुझे यह नहीं पता है कि यह कैसे लिखा जाता है।

मैंने कोशिश की:

grep 'word1\|word2' text.txt
grep word1 word2 text.txt
grep word1 text.txt | grep word2
grep 'word1\^word2' text.txt

और भी बहुत कुछ, लेकिन सक्सेज नहीं मिल सका।

जवाबों:


6

grep 'word1\|word2' text.txtयुक्त लाइनों के लिए खोज word1या word2। इसमें ऐसी लाइनें शामिल हैं जिनमें दोनों शामिल हैं।

grep word1 text.txt | grep word2युक्त लाइनों के लिए खोज word1और word2। दो शब्द ओवरलैप कर सकते हैं (उदाहरण के लिए और foobarशामिल हैं )। दोनों शब्दों वाली लाइनों की खोज करने का एक और तरीका, लेकिन केवल एक गैर-अतिव्यापी तरीके से, या तो क्रम में उनके लिए खोज करना है:fooobgrep 'word1.*word2\|word2.*word1' text.txt

grep word1 text.txt | grep -v word2युक्त पंक्तियों के लिए खोज करता है, word1लेकिन नहीं word2-vविकल्प के सामने के बजाय, न खाने वाले लाइनों और निकालने मिलान लाइनों रखने के लिए ग्रेप बताता है। यह आपको आपके इच्छित आधे परिणाम देता है। सममित खोज को जोड़कर, आपको सभी पंक्तियाँ मिलती हैं जिनमें एक शब्द भी शामिल है।

grep word1 text.txt | grep -v word2
grep word2 text.txt | grep -v word1

वैकल्पिक रूप से, आप दोनों शब्दों वाली लाइनों से शुरू कर सकते हैं, और दोनों शब्दों वाली लाइनों को हटा सकते हैं। उपरोक्त बिल्डिंग ब्लॉक्स को देखते हुए, यह आसान है अगर शब्द ओवरलैप नहीं होते हैं।

grep 'word1\|word2' text.txt | grep -v 'word1.*word2\|word2.*word1'

धन्यवाद, यह वही है जिसकी मुझे तलाश थी। अन्य उत्तर भी बहुत दिलचस्प हैं ताकि उन पर गौर किया जाए। योगदान के लिए आप सभी का धन्यवाद।
लुकली

17

GNU के साथ awk:

$ printf '%s\n' {foo,bar}{bar,foo} neither | gawk 'xor(/foo/,/bar/)'
foofoo
barbar

या आंशिक रूप से:

awk '((/foo/) + (/bar/)) % 2'

एक साथ grepके लिए के साथ समर्थन -P(PCRE):

grep -P '^((?=.*foo)(?!.*bar)|(?=.*bar)(?!.*foo))'

के साथ sed:

sed '
  /foo/{
    /bar/d
    b
  }
  /bar/!d'

आप केवल संपूर्ण शब्दों को विचार करने के लिए (न तो है कि वहाँ चाहते हैं fooऔर न ही barमें foobarया barbarउदाहरण के लिए), आप तय करने के लिए कैसे उन शब्दों को सीमांकित कर रहे हैं देख सकते हैं। यदि यह अक्षरों, अंकों और अंडरस्कोर के अलावा किसी भी वर्ण द्वारा -wहोता है जैसे कई grepकार्यान्वयन का विकल्प होता है, तो आप उन लोगों को बदल देंगे:

gawk 'xor(/\<foo\>/,/\<bar\>/)'
awk '((/(^|[^[:alnum:]_)foo([^[:alnum:]_]|$)/) + \
      (/(^|[^[:alnum:]_)bar([^[:alnum:]_]|$)/)) % 2'
grep -P '^((?=.*\bfoo\b)(?!.*\bbar\b)|(?=.*\bbar\b)(?!.*\bfoo\b))'

के लिए sedहै कि एक सा जटिल जब तक आप एक है हो जाता है sedजीएनयू तरह कार्यान्वयन sed कि समर्थन करता है \</ \>जीएनयू की तरह शब्द सीमाओं के रूप में awkकरता है।


6
स्टीफन, कृपया शेल स्क्रिप्टिंग के बारे में एक किताब लिखें!
pfnuesel

क्षमा करें, मैंने केवल कुछ सप्ताह पहले कमांड लाइन शुरू की थी। मैं इसे केवल शब्दों की खोज के लिए कैसे बाध्य करूंगा? मैंने -w और -wP की कोशिश की, लेकिन इसने मुझे गलत आउटपुट दिया। मैंने * word1 / * word2 और word1 / word2 के आसपास '' का उपयोग करने की भी कोशिश की।
लुकली

@ लकली, देखें संपादन।
स्टीफन चेजेलस

2

एक बैश समाधान:

#!/bin/bash 
while (( $# )); do
    a=0 ; [[ $1 =~ foo ]] && a=1 
    b=0 ; [[ $1 =~ bar ]] && b=1
    (( a ^ b )) && echo "$1"
    shift
done

इसका परीक्षण करने के लिए:

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