Відповіді:
Інший інструмент, ніж grepце шлях.
Наприклад, використовуючи команду perl:
perl -ne 'print if /pattern1/ xor /pattern2/'
perl -neвиконує команду, задану над кожним рядком stdin, яка в цьому випадку друкує рядок, якщо вона збігається /pattern1/ xor /pattern2/, або іншими словами відповідає одному шаблону, але не іншому (виключно або).
Це працює для шаблону в будь-якому порядку, і має мати кращу продуктивність, ніж кілька викликів grep, а також менше набирати текст.
Або, ще коротше, з awk:
awk 'xor(/pattern1/,/pattern2/)'
або для версій awk, у яких немає xor:
awk '/pattern1/+/pattern2/==1`
xorдоступний лише в GNU Awk?
/pattern1/+/pattern2/==1ir xorвідсутній.
\b) у самих шаблонах, тобто \bword\b.
Спробуйте з 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- віддайте перевагуgrep -E
-fта -eпараметри, хоча старший egrepі fgrepбуде підтримуватися деякий час.
grep(який підтримує -F, -E, -e, , -fяк POSIX вимагає) в /usr/xpg4/bin. Комунальні послуги в /binзастарілих.
З grepреалізаціями, які підтримують регулярні вирази, подібні до perl (наприклад, pcregrepGNU або ast-open grep -P), ви можете це зробити за один grepвиклик за допомогою:
grep -P '^(?=.*pat1)(?!.*pat2)|^(?=.*pat2)(?!.*pat1)'
Тобто знаходьте рядки, які відповідають, pat1але ні pat2, pat2але ні pat1.
(?=...)і (?!...), відповідно, дивляться вперед і негативно дивляться вперед оператори. Тож технічно, вищезазначене шукає початок теми ( ^) за умови, що за ним слідує, .*pat1а не слідує за ним .*pat2, або те саме з pat1і pat2перевернуто.
Це субоптимально для ліній, що містять обидва візерунки, як їх би потім шукали двічі. Ви можете замість цього використовувати більш просунуті оператори perl, такі як:
grep -P '^(?=.*pat1|())(?(1)(?=.*pat2)|(?!.*pat2))'
(?(1)yespattern|nopattern)відповідає проти, yespatternякщо група захоплення 1st (порожня ()вгорі) збігається та nopatternінше. Якщо це ()збіг, це означає, що pat1не відповідало, тому ми шукаємо pat2(позитивний погляд вперед), а ми шукаємо не pat2 інакше (негативний погляд вперед).
З sed, ви можете написати це:
sed -ne '/pat1/{/pat2/!p;d;}' -e '/pat2/p'
grep: the -P option only supports a single pattern, принаймні в кожній системі, до якої я маю доступ. Хоча +1 для вашого другого рішення.
grep. pcregrepі у аст-відкритого грепу немає такої проблеми. Я замінив множину -eоператором змінної RE, тому він повинен працювати і з GNU grep.
Булево, ви шукаєте A xor B, який можна записати як
(А, а не В)
або
(B, а не A)
Зважаючи на те, що у вашому запитанні не згадується, що ви переймаєтесь порядком виводу, доки не відображаються відповідні рядки, булеве розширення A xor B досить чорно просте:
$ 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.
Для наступного прикладу:
# Patterns:
# apple
# pear
# Example line
line="a_apple_apple_pear_a"
Це може бути зроблено виключно з grep -E, uniqі wc.
# Grep for regex pattern, sort as unique, and count the number of lines
result=$(grep -oE 'apple|pear' <<< $line | sort -u | wc -l)
Якщо grepкомпілюється з регулярними виразами Perl, то ви можете зіставитись з останньою появою, а не з необхідністю передавати на uniq:
# Grep for regex pattern and count the number of lines
result=$(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l)
Виведіть результат:
# 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
Одноколісний:
(($(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l) == 1)) && echo Only one word matched
Якщо ви не хочете жорстко кодувати шаблон, складання його зі змінним набором елементів може бути автоматизовано функцією.
Це також можна зробити на Bash як функція без труб або додаткових процесів, але це буде більше задіяне і, ймовірно, не входить у сферу вашого питання.
Big apple\nі pear-shaped\n, то вихід повинен містити обидва ці рядки. Ваше рішення отримає кількість 2; довга версія повідомляла б, що "обидва слова відповідають" (це відповідь на неправильне запитання), а коротка версія нічого не скаже. (3) Пропозиція: використання -oтут - це дуже погана ідея, оскільки вона приховує рядки, що містять відповідність, тому ви не бачите, коли обидва слова з’являються в одному рядку. … (Продовжував)
uniq/ sort -uі вигадливий регулярний вираз Perl для відповідності лише останньому випадку в кожному рядку насправді не доповнює корисну відповідь на це запитання. Але навіть якщо вони це зробили, це все одно буде поганою відповіддю, оскільки ви не пояснюєте, як вони сприяють відповіді на питання. (Див. Відповідь Стефана Шазеласа на прикладі хорошого пояснення.)
[a-z][a-z0-9]\(,7\}\(\.[a-z0-9]\{,3\}\)+? (2) Що робити, якщо одне зі слів / зразків з’являється в рядку декілька разів (а інше не з’являється)? Це еквівалент слово, яке з’являється один раз, або воно вважається численним випадком?