Je souhaite rechercher des lignes avec 'Word1' XOR 'Word2' dans un fichier texte. Donc, il devrait produire des lignes avec Word1, Word2 mais pas les lignes avec ces deux mots. Je voulais Utilisez le XOR mais je ne sais pas comment écrire cela dans la ligne de commande Linux.
J'ai essayé:
grep 'Word1\|Word2' text.txt
grep Word1 Word2 text.txt
grep Word1 text.txt | grep Word2
grep 'Word1\^Word2' text.txt
et beaucoup plus, mais ne pouvaient pas réussir.
grep 'Word1\|Word2' text.txt
Recherche des lignes contenant Word1
ou Word2
. Cela inclut des lignes contenant les deux.
grep Word1 text.txt | grep Word2
Recherche des lignes contenant Word1
et Word2
. Les deux mots peuvent se chevaucher (par ex. foobar
contient foo
et ob
). Une autre façon de rechercher des lignes contenant à la fois des mots, mais uniquement de manière non chevauchante, est de les rechercher dans l'un ou l'autre ordre: grep 'Word1.*Word2\|Word2.*Word1' text.txt
grep Word1 text.txt | grep -v Word2
Recherche des lignes contenant Word1
mais non Word2
. Les -v
L'option indique à Grep de conserver des lignes non correspondantes et de supprimer les lignes correspondantes, au lieu de l'opposé. Cela vous donne la moitié des résultats que vous vouliez. En ajoutant la recherche symétrique, vous obtenez toutes les lignes contenant exactement l'un des mots.
grep Word1 text.txt | grep -v Word2
grep Word2 text.txt | grep -v Word1
Alternativement, vous pouvez commencer par les lignes contenant des mots et retirer les lignes contenant les deux mots. Compte tenu des blocs de construction ci-dessus, cela est facile si les mots ne se chevauchent pas.
grep 'Word1\|Word2' text.txt | grep -v 'Word1.*Word2\|Word2.*Word1'
Avec GNU awk
:
$ printf '%s\n' {foo,bar}{bar,foo} neither | gawk 'xor(/foo/,/bar/)'
foofoo
barbar
Ou portablement:
awk '((/foo/) + (/bar/)) % 2'
Avec un grep
avec support pour -P
(PCRE):
grep -P '^((?=.*foo)(?!.*bar)|(?=.*bar)(?!.*foo))'
Avec sed
:
sed '
/foo/{
/bar/d
b
}
/bar/!d'
Si vous souhaitez considérer les mots entiers uniquement (qu'il n'y a ni foo
ni bar
in foobar
ou barbar
par exemple), vous devez décider. Comment ces mots sont délimités. Si c'est par n'importe quel caractère autre que les lettres, les chiffres et le soulignement comme le -w
option de plusieurs grep
_ La mise en œuvre, alors vous changeriez celles-ci pour:
gawk 'xor(/\<foo\>/,/\<bar\>/)'
awk '((/(^|[^[:alnum:]_)foo([^[:alnum:]_]|$)/) + \
(/(^|[^[:alnum:]_)bar([^[:alnum:]_]|$)/)) % 2'
grep -P '^((?=.*\bfoo\b)(?!.*\bbar\b)|(?=.*\bbar\b)(?!.*\bfoo\b))'
Pour sed
qui devient un peu compliqué à moins que vous ayez une implémentation sed
comme GNU sed
qui prend en charge \<
/\>
comme limites de mots comme GNU awk
fait.
Une solution bash:
#!/bin/bash
while (( $# )); do
a=0 ; [[ $1 =~ foo ]] && a=1
b=0 ; [[ $1 =~ bar ]] && b=1
(( a ^ b )) && echo "$1"
shift
done
Pour le tester:
$ ./script {foo,bar}\ {foo,bar} neither
foo foo
bar bar