回答:
grep 'word1\|word2' text.txt
word1
またはを含む行を検索しますword2
。これには、両方を含む行が含まれます。
grep word1 text.txt | grep word2
含む行を検索word1
してword2
。二つの言葉は、(例えば重複することができますfoobar
含まれていfoo
とob
)。両方の単語を含むが重複しない方法でのみ行を検索する別の方法は、次のいずれかの順序で検索することです。grep 'word1.*word2\|word2.*word1' text.txt
grep word1 text.txt | grep -v word2
を含むword1
が含まない行を検索しますword2
。この-v
オプションは、grepに、一致しない行を維持し、一致する行を削除するように指示します。これにより、期待した結果の半分が得られます。対称検索を追加すると、単語の1つだけを含むすべての行が得られます。
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'
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
GNUのような実装をsed
サポートしていること\<
/ \>
GNUのような単語の境界としてawk
行います。
bashソリューション:
#!/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