grepを使用して2つの単語のうち1つのみを含め、両方を含まない行を検索するにはどうすればよいですか? [コピー]

grepを使用して2つの単語のうち1つのみを含め、両方を含まない行を検索するにはどうすればよいですか? [コピー]

"word1" XOR "word2"を含む行をテキストファイルから検索したいです。したがって、word1、word2を含む行を出力する必要がありますが、これら2つの単語を含む行は出力しないでください。 XORを使いたいのですが、Linuxのコマンドラインで書く方法がわかりません。

私は試した:

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

などがありましたが、すべて失敗しました。

答え1

GNUの使用awk:

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

または携帯用:

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

サポート(grepPCRE -P):

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

そしてsed

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

foo完全な単語(たとえば、nor barinfoobarまたはin)のみを考慮する場合は、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))'

/を単語境界としてサポートするGNUのような実装がsedなければ、これは少し複雑になるからです。sedsed\<\>awk

答え2

grep 'word1\|word2' text.txtword1またはを含む行を検索しますword2。これには両方を含む行が含まれます。

grep word1 text.txt | grep word2word1と を含む行を検索しますword2。 2つの単語が重なっている可能性があります(例:foobar埋め込みfooob)。 2つの単語を含む行を検索する別の方法(重複しない方法でのみ)は、任意の順序で検索することです。grep 'word1.*word2\|word2.*word1' text.txt

grep word1 text.txt | grep -v word2word1を含むが含まない行を検索しますword2。この-vオプションは、grep に一致しない行を維持し、一致する行を削除するように指示します。これにより、目的の結果の半分を得ることができます。対称検索を追加すると、正確に特定の単語を含むすべての行を取得できます。

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'

答え3

バッシュソリューション:

#!/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

関連情報