Как использовать grep для поиска строки с одним из двух слов, но не с обоими?
11
Я хочу найти строки с 'word1' XOR 'word2' в текстовом файле. Таким образом, он должен вывести строки с word1, word2, но не с обоими этими словами. Я хотел использовать XOR, но я не знаю, как написать это в командной строке Linux.
grep 'word1\|word2' text.txtищет строки, содержащие word1или word2. Это включает в себя строки, которые содержат оба.
grep word1 text.txt | grep word2ищет строки, содержащие word1и word2. Два слова могут перекрываться (например, foobarсодержит fooи ob). Другой способ поиска строк, содержащих оба слова, но только непересекающимся способом, состоит в том, чтобы искать их в любом порядке:grep 'word1.*word2\|word2.*word1' text.txt
grep word1 text.txt | grep -v word2ищет строки, содержащие word1но не word2. -vОпция говорит Grep держать несовпадающие линии и соответсвующие удалить строки, а не наоборот. Это дает вам половину результатов, которые вы хотели. Добавляя симметричный поиск, вы получаете все строки, содержащие ровно одно из слов.
Кроме того, вы можете начать со строк, содержащих любое слово, и удалить строки, содержащие оба слова. Учитывая строительные блоки выше, это легко, если слова не пересекаются.
Если вы хотите , чтобы рассмотреть только целые слова (что не является ни , fooни barв foobarили barbar, например), то вы должны решить , как эти слова разделены. Если это какой-либо символ, отличный от букв, цифр и подчеркивания, как во -wмногих вариантах grepреализации, то вы бы изменили их на:
Для sedэто становится немного сложнее , если у вас есть sedреализация , как GNU , sed которая поддерживает \</ , \>как границы слов , как GNU awkделает.
Стефан, пожалуйста, напиши книгу о сценариях оболочки!
pfnuesel
Извините, я только запустил командную строку несколько недель назад. Как бы я заставил его искать только слова? Я пробовал -Pw и -wP, но это дало мне неправильный вывод. Я также пытался использовать '' между * word1 / * word2 и вокруг word1 / word2.
Лукали
@Lukali, см. Редактировать.
Стефан Шазелас
2
Решение Bash:
#!/bin/bash
while (( $# )); do
a=0 ; [[ $1 =~ foo ]] && a=1
b=0 ; [[ $1 =~ bar ]] && b=1
(( a ^ b )) && echo "$1"
shift
done
Чтобы проверить это:
$ ./script {foo,bar}\ {foo,bar} neither
foo foo
bar bar
С GNU
awk
:Или переносимо:
С
grep
поддержкой-P
(PCRE):С
sed
:Если вы хотите , чтобы рассмотреть только целые слова (что не является ни ,
foo
ниbar
вfoobar
илиbarbar
, например), то вы должны решить , как эти слова разделены. Если это какой-либо символ, отличный от букв, цифр и подчеркивания, как во-w
многих вариантахgrep
реализации, то вы бы изменили их на:Для
sed
это становится немного сложнее , если у вас естьsed
реализация , как GNU ,sed
которая поддерживает\<
/ ,\>
как границы слов , как GNUawk
делает.источник
Решение Bash:
Чтобы проверить это:
источник