Ответы:
Инструмент, отличный grepот пути.
Например, используя perl, команда будет:
perl -ne 'print if /pattern1/ xor /pattern2/'
perl -neвыполняет команду, заданную для каждой строки стандартного ввода, которая в этом случае печатает строку, если она соответствует /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-подобные регулярные выражения (например, pcregrepили GNU, или 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 st (пустой ()сверху), и в 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и у ast-open grep такой проблемы нет. Я заменил -eмножитель оператором чередования RE, поэтому grepтеперь он должен работать и с GNU .
В логических терминах вы ищете A xor B, который можно записать как
(А, а не В)
или
(Б а не А)
Учитывая, что в вашем вопросе не упоминается, что вы обеспокоены порядком вывода, пока отображаются соответствующие строки, логическое расширение A xor B чертовски просто в 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.
Для следующего примера:
# 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) Что, если одно из слов / шаблонов появляется более одного раза в строке (а другое не появляется)? Это эквивалентно тому, что слово появляется один раз, или оно считается как несколько вхождений?