Como usar o grep para procurar uma linha com uma das duas palavras, mas não ambas?
11
Eu quero procurar linhas com 'word1' XOR 'word2' em um arquivo de texto. Portanto, deve exibir linhas com a palavra 1, palavra 2, mas não as linhas com ambas as palavras. Eu queria usar o XOR, mas não sei como escrever isso na linha de comando do Linux.
grep 'word1\|word2' text.txtprocura por linhas contendo word1ou word2. Isso inclui linhas que contêm ambos.
grep word1 text.txt | grep word2procura por linhas contendo word1e word2. As duas palavras podem se sobrepor (por exemplo, foobarcontém fooe ob). Outra maneira de procurar linhas contendo as duas palavras, mas apenas de maneira não sobreposta, é procurá-las em qualquer ordem:grep 'word1.*word2\|word2.*word1' text.txt
grep word1 text.txt | grep -v word2procura por linhas contendo word1mas não word2. A -vopção diz ao grep para manter as linhas não correspondentes e remover as linhas correspondentes, em vez do oposto. Isso fornece metade dos resultados desejados. Ao adicionar a pesquisa simétrica, você obtém todas as linhas que contêm exatamente uma das palavras.
Como alternativa, você pode começar pelas linhas que contêm uma das palavras e remover as linhas que contêm as duas palavras. Dado os blocos de construção acima, isso é fácil se as palavras não se sobrepuserem.
Obrigado, isto é exatamente o que eu estava procurando. As outras respostas também são muito interessantes, então, mal olhe para elas. Obrigado a todos por contribuir.
Se você considerar apenas palavras inteiras (que não é nem foonem barem foobarou barbarpor exemplo), você precisa decidir como essas palavras são delimitados. Se for por qualquer caractere que não seja letras, dígitos e sublinhado, como a -wopção de muitas grepimplementações, altere-os para:
Stephane, por favor escreva um livro sobre scripts de shell!
pfnuesel
Desculpe, só iniciei a linha de comando há algumas semanas. Como eu o forçaria a procurar apenas palavras? Tentei -Pw e -wP, mas isso me deu a saída errada. Também tentei usar '' entre * word1 / * word2 e em torno de word1 / word2.
Lukali
@Lukali, veja editar.
Stéphane Chazelas
2
Uma solução bash:
#!/bin/bash
while (( $# )); do
a=0 ; [[ $1 =~ foo ]] && a=1
b=0 ; [[ $1 =~ bar ]] && b=1
(( a ^ b )) && echo "$1"
shift
done
Para testá-lo:
$ ./script {foo,bar}\ {foo,bar} neither
foo foo
bar bar
Com o GNU
awk
:Ou portably:
Com um
grep
suporte para-P
(PCRE):Com
sed
:Se você considerar apenas palavras inteiras (que não é nem
foo
nembar
emfoobar
oubarbar
por exemplo), você precisa decidir como essas palavras são delimitados. Se for por qualquer caractere que não seja letras, dígitos e sublinhado, como a-w
opção de muitasgrep
implementações, altere-os para:Por
sed
que se torna um pouco complicado se não tiver umased
aplicação como o GNUsed
que suporta\<
/\>
como limites da palavra como o GNUawk
faz.fonte
Uma solução bash:
Para testá-lo:
fonte