Odpowiedzi:
Narzędzie inne niż grepjest do zrobienia.
Na przykład, używając perla, komenda wyglądałaby następująco:
perl -ne 'print if /pattern1/ xor /pattern2/'
perl -neuruchamia polecenie podane dla każdej linii standardowej, która w tym przypadku wypisuje linię, jeśli pasuje /pattern1/ xor /pattern2/, lub innymi słowy dopasowuje jeden wzór, ale nie drugi (wyłączny lub).
Działa to dla wzorca w dowolnej kolejności i powinno mieć lepszą wydajność niż wiele wywołań grep, a także mniej pisania.
Lub, nawet krócej, z awk:
awk 'xor(/pattern1/,/pattern2/)'
lub dla wersji awk, które nie mają xor:
awk '/pattern1/+/pattern2/==1`
xordostępny tylko w GNU Awk?
/pattern1/+/pattern2/==1ir xor.
\b) w samych wzorcach, tj \bword\b.
Spróbuj z egrep
egrep 'pattern1|pattern2' file | grep -v -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'
grep -e foo -e bar | grep -v -e 'foo.*bar' -e 'bar.*foo'
Direct invocation as either egrep or fgrep is deprecated- preferujgrep -E
-fi -eopcje, chociaż są starsze egrepi fgrepbędą przez jakiś czas obsługiwane.
grep(to podpory -F, -E, -e, -fjak tego wymaga POSIX) jest /usr/xpg4/bin. Narzędzia w /binsą przestarzałe.
Dzięki grepimplementacjom, które obsługują wyrażenia regularne podobne do perla (jak pcregreplub GNU lub ast-open grep -P), możesz to zrobić za pomocą jednego grepwywołania za pomocą:
grep -P '^(?=.*pat1)(?!.*pat2)|^(?=.*pat2)(?!.*pat1)'
To jest znaleźć linie, które pasują, pat1ale nie pat2, pat2ale nie pat1.
(?=...)i (?!...)są odpowiednio operatorami perspektywicznymi i negatywnymi. Tak więc technicznie powyższe wygląda na początek tematu ( ^) pod warunkiem, że następuje po nim .*pat1i nie następuje po nim .*pat2, lub to samo z pat1i pat2odwrócone.
Jest to nieoptymalne dla linii zawierających oba wzorce, ponieważ byłyby wówczas dwukrotnie wyszukiwane. Zamiast tego możesz użyć bardziej zaawansowanych operatorów perla, takich jak:
grep -P '^(?=.*pat1|())(?(1)(?=.*pat2)|(?!.*pat2))'
(?(1)yespattern|nopattern)pasuje do, yespatternjeśli grupa przechwytywania 1st (pusta ()powyżej) jest zgodna, i nopatterninaczej. Jeśli to ()mecze, że środki pat1nie są zgodne, więc szukamy pat2(pozytywnego spojrzenia w przyszłość) i patrzymy na nie pat2 inaczej (negatywny patrzeć w przyszłość).
Za pomocą sedmożesz to napisać:
sed -ne '/pat1/{/pat2/!p;d;}' -e '/pat2/p'
grep: the -P option only supports a single pattern, przynajmniej na każdym systemie, do którego mam dostęp. +1 za drugie rozwiązanie.
grep. pcregrepa ast-open grep nie ma tego problemu. Zamieniłem wielokrotność -ena alternatywny operator RE, więc powinien on działać również z GNU grep.
Mówiąc logicznie, szukasz A xor B, który można zapisać jako
(A i nie B)
lub
(B i nie A)
Biorąc pod uwagę, że twoje pytanie nie wspomina, że zajmujesz się kolejnością danych wyjściowych, o ile wyświetlane są pasujące linie, rozszerzenie boolowskie A xor B jest dość proste w grep:
$ cat << EOF > foo
> a b
> a
> b
> c a
> c b
> b a
> b c
> EOF
$ grep -w 'a' foo | grep -vw 'b'; grep -w 'b' foo | grep -vw 'a';
a
c a
b
c b
b c
sort | uniq.
Dla następującego przykładu:
# Patterns:
# apple
# pear
# Example line
line="a_apple_apple_pear_a"
Można to zrobić wyłącznie z grep -E, uniq, i wc.
# Grep for regex pattern, sort as unique, and count the number of lines
result=$(grep -oE 'apple|pear' <<< $line | sort -u | wc -l)
Jeśli grepjest skompilowany z wyrażeniami regularnymi Perla, możesz dopasować do ostatniego wystąpienia, zamiast konieczności potoku do uniq:
# Grep for regex pattern and count the number of lines
result=$(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l)
Wynik:
# Only one of the words exists if the result is < 2
((result > 0)) &&
if (($result < 2)); then
echo Only one word matched
else
echo Both words matched
fi
Jednowarstwowy:
(($(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l) == 1)) && echo Only one word matched
Jeśli nie chcesz na stałe kodować wzorca, składanie go ze zmiennym zestawem elementów można zautomatyzować za pomocą funkcji.
Można to również zrobić natywnie w Bash jako funkcję bez rur lub dodatkowych procesów, ale byłby bardziej zaangażowany i prawdopodobnie nie wchodzi w zakres twojego pytania.
Big apple\ni pear-shaped\n, następnie wyjście powinno zawierać zarówno tych linii. Twoje rozwiązanie uzyskałoby liczbę 2; w długiej wersji będzie napisane „Dopasowane oba słowa” (co jest odpowiedzią na złe pytanie), a w krótkiej wersji nic nie powie. (3) Sugestia: użycie -otutaj jest naprawdę złym pomysłem, ponieważ ukrywa wiersze zawierające dopasowania, więc nie możesz zobaczyć, kiedy oba słowa pojawiają się w tym samym wierszu. … (Ciąg dalszy)
uniq/ sort -ui fantazyjnego wyrażenia regularnego Perla, by dopasować tylko ostatnie wystąpienie w każdym wierszu, tak naprawdę nie stanowi użytecznej odpowiedzi na to pytanie. Ale nawet gdyby tak było, nadal byłaby to zła odpowiedź, ponieważ nie wyjaśnisz, w jaki sposób przyczyniają się do udzielenia odpowiedzi na pytanie. (Zobacz odpowiedź Stéphane'a Chazelasa na przykład dobrego wyjaśnienia.)
[a-z][a-z0-9]\(,7\}\(\.[a-z0-9]\{,3\}\)+? (2) Co się stanie, jeśli jedno ze słów / wzorów pojawi się więcej niż jeden raz w linii (a drugie nie pojawi się)? Czy jest to równoważne słowu występującemu raz, czy też liczy się jako wielokrotne wystąpienie?