grep을 사용하여 두 단어 중 하나만있는 줄을 검색하는 방법


11

텍스트 파일에서 'word1'XOR 'word2'가있는 줄을 검색하고 싶습니다. 따라서 word1, word2가있는 행을 출력해야하지만이 단어가 모두있는 행은 출력하지 않아야합니다. XOR을 사용하고 싶었지만 Linux 명령 줄에 작성하는 방법을 모르겠습니다.

나는 시도했다 :

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포함 foo하고 ob). 겹치지 않는 방식으로 만 두 단어를 모두 포함하는 행을 검색하는 다른 방법은 다음 순서로 검색하는 것입니다.grep 'word1.*word2\|word2.*word1' text.txt

grep word1 text.txt | grep -v word2포함 word1하지만 포함 하지 않는 행을 검색합니다 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'

이것이 내가 찾던 것입니다. 다른 답변도 매우 흥미로워 서 잘못 살펴 봅니다. 기부 해 주셔서 감사합니다.
Lukali

17

GNU로 awk:

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

또는 휴대용으로 :

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

A를 grep위한과 지원 -P(PCRE) :

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

sed:

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

당신이 (어느 쪽이 없음을 전체 단어 만 고려할 경우 foobarfoobar또는 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그 당신이하지 않는 한 조금 복잡하게 sedGNU처럼 구현을 sed 지원하는 \</ \>GNU와 같은 단어 경계로 awk한다.


6
스테판, 쉘 스크립팅에 관한 책을 써주세요!
pfnuesel

몇 주 전에 명령 줄을 시작한 것이 유감입니다. 단어 만 검색하도록하려면 어떻게해야합니까? 나는 -Pw와 -wP를 시도했지만 이것은 나에게 잘못된 결과를 주었다. 또한 * word1 / * word2와 word1 / word2 사이에 ''를 사용하려고했습니다.
Lukali

@Lukali, 편집 참조.
Stéphane Chazelas

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.