Jak używać grep do wyszukiwania linii z jednym z dwóch słów, ale nie z obydwoma?
11
Chcę wyszukać wiersze ze słowem „słowo 1” XOR „słowo 2” w pliku tekstowym. Powinien więc wypisywać wiersze ze słowem1, słowem2, ale nie wiersze z tymi dwoma słowami. Chciałem użyć XOR, ale nie wiem, jak napisać to w wierszu poleceń systemu Linux.
grep 'word1\|word2' text.txtwyszukuje wiersze zawierające word1lub word2. Obejmuje to wiersze zawierające oba te elementy.
grep word1 text.txt | grep word2wyszukuje wiersze zawierające word1i word2. Te dwa słowa mogą się nakładać (np. foobarZawiera fooi ob). Innym sposobem wyszukiwania wierszy zawierających oba słowa, ale tylko w sposób nienakładający się, jest wyszukiwanie ich w dowolnej kolejności:grep 'word1.*word2\|word2.*word1' text.txt
grep word1 text.txt | grep -v word2wyszukuje wiersze zawierające, word1ale nie word2. Ta -vopcja mówi grepowi, aby zachowywał niepasujące linie i usuwał pasujące linie zamiast odwrotnie. To daje połowę pożądanych rezultatów. Dodając wyszukiwanie symetryczne, otrzymujesz wszystkie wiersze zawierające dokładnie jedno ze słów.
Alternatywnie możesz zacząć od linii zawierających jedno ze słów i usunąć linie zawierające oba słowa. Biorąc pod uwagę powyższe elementy, jest to łatwe, jeśli słowa się nie nakładają.
Jeśli chcesz wziąć pod uwagę tylko całe słowa (które nie jest ani fooani barw foobarlub barbarna przykład), to musisz zdecydować, w jaki sposób te słowa są ograniczone. Jeśli jest to jakikolwiek znak inny niż litery, cyfry i podkreślniki, jak w -wprzypadku wielu grepimplementacji, możesz zmienić je na:
Przepraszam, że uruchomiłem wiersz poleceń dopiero kilka tygodni temu. Jak zmusić go do wyszukiwania tylko słów? Próbowałem -Pw i -wP, ale to dało mi zły wynik. Próbowałem także użyć „” między * słowem1 / * słowem2 a wokół słowa1 / słowa2.
Lukali
@Lukali, patrz edycja.
Stéphane Chazelas
2
Rozwiązanie bash:
#!/bin/bash
while (( $# )); do
a=0 ; [[ $1 =~ foo ]] && a=1
b=0 ; [[ $1 =~ bar ]] && b=1
(( a ^ b )) && echo "$1"
shift
done
Aby to przetestować:
$ ./script {foo,bar}\ {foo,bar} neither
foo foo
bar bar
Z GNU
awk
:Lub przenośnie:
Dzięki
grep
wsparciu dla-P
(PCRE):Z
sed
:Jeśli chcesz wziąć pod uwagę tylko całe słowa (które nie jest ani
foo
anibar
wfoobar
lubbarbar
na przykład), to musisz zdecydować, w jaki sposób te słowa są ograniczone. Jeśli jest to jakikolwiek znak inny niż litery, cyfry i podkreślniki, jak w-w
przypadku wielugrep
implementacji, możesz zmienić je na:To
sed
staje się nieco skomplikowane, chyba że maszsed
implementację taką jak GNU,sed
która obsługuje\<
/\>
jak granice słów jak GNUawk
.źródło
Rozwiązanie bash:
Aby to przetestować:
źródło