Как использовать grep, исключая некоторые шаблоны?

87

Я хотел бы найти в файлах строки, в которых присутствует какой-то узор и отсутствует какой-то другой. Например, мне нужно найти все файлы / строки, в том числе, loomкроме файлов с расширением gloom. Итак, я могу найти loomс помощью команды:

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Теперь я хочу искать loomисключая gloom. Однако обе следующие команды завершились неудачно:

grep -v 'gloom' -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
grep -n 'loom' -v 'gloom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Что мне делать, чтобы достичь своей цели?

РЕДАКТИРОВАТЬ 1: Я имею в виду, чтоloomиgloomявляются последовательностями символов (не обязательно словами). Итак, мне нужно, например,bloombergв выводе команды и не нужноungloomy.

РЕДАКТИРОВАТЬ 2: Это образец моих ожиданий. Обе следующие строки находятся в выводе команды:

Я столкнулся с иконами, вырисовывающимися сквозь пелену ладана.

Arty является slooming в мрачный день.

Обе следующие строки отсутствуют в выводе команды:

Это мрачно , черт возьми, ужасно - огромные тупицы тупицы.

На юго-западе вокруг холла высоких pyntit

Ткацкий станок
источник
Вы ищете файлы, соответствующие вашим критериям строк, соответствующих вашим критериям?
Джуто
Я ищу файлы со строками, соответствующими моим критериям. И я хочу увидеть список всех наборов имя файла + номер совпадающей строки + саму совпадающую строку.
Loom
Если бы линия была there is a loom in the gloom- вы бы хотели напечатать эту строку? Просто пытаюсь понять, ищете ли вы просто линии, в которых ткацкий станок встречается не как часть мрака, или действительно хотите исключить строки, содержащие мрак, даже если ткацкий станок появляется сам по себе в другом месте линии. Поможет публикация некоторого образца ввода и ожидаемого вывода.
Эд Мортон
Так ваш вопрос действительно How do I find lines containing the string "loom" where "loom" is not preceded by the letter "g"? Если бы вы опубликовали образец ввода и желаемый результат, это очень помогло бы. Ответ на этот вопрос содержится в ответах ниже.
Эд Мортон
1
@EdMorton - Да, вы правы - мне нужны все строки, где встречается loomбез предисловия g. (Мне очень жаль. Я начал комментировать вчера, но так и не закончил. Случайно этот комментарий был отправлен.)
Loom

Ответы:

105

Как насчет того, чтобы просто связать greps?

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
Houbysoft
источник
13
Вовремя. Отлично работает. -v - вариант исключения. Спасибо
Рави Кришна П.
2
Из вопроса: Значит, мне нужно, например, bloombergв выводе команды, а не нужно ungloomy. Если бы одна строка содержала «… и bloomberg не слишком мрачен в отношении перспектив…», вы бы исключили эту строку, но она нужна (потому что if содержит bloomberg).
Джонатан Леффлер
23

Другое решение без цепочки grep :

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Между скобками вы исключаете символ gперед любым появлением loom, если только loomэто не первые символы строки.

Бентой13
источник
9

Старовато, ну да ладно ...

Решение от @houbysoft, получившее наибольшее количество голосов, не будет работать, так как оно исключит любую строку со словом «мрак», даже если в нем есть слово «loom». Согласно ожиданиям OP, нам нужно включить строки с «ткацким станком», даже если в них тоже есть «мрак». Эта строка должна быть в выводе "Arty плывет в пасмурный день.", Но это будет исключено цепочкой grep, например

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'

Вместо этого Bentoy13 работает лучше , чем пример регулярного выражения egrep.

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

поскольку он будет включать в себя любую строку со словом «loom», независимо от того, есть ли в нем «мрачность» или нет. С другой стороны, если в нем есть только мрак, он не будет включать его, а это именно то поведение, которого хочет OP.

Сэм
источник
8

Просто используйте awk, это намного проще, чем grep, позволяя четко выражать составные условия.

Если вы хотите пропустить строки, содержащие loomи gloom:

awk '/loom/ && !/gloom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

или если вы хотите их распечатать:

awk '/(^|[^g])loom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

и если на самом деле вам просто нужны строки, которые loomпоявляются как слово само по себе:

awk '/\<loom\>/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)
Эд Мортон
источник
3
Подумайте, как написать команду grep для получения строк, содержащих abcи defи ghiв любом порядке. Теперь сравните это с awk '/abc/ && /def/ && /ghi/'. Теперь подумайте о том, как awk '/loom/ && !/gloom/'в ответах на этой странице записывается эквивалент grep .
Эд Мортон
Я не очень знаком с awk, по всей видимости, есть книги об этой команде как таковой. Пока меня устраивает grep, возможно, однажды я скажу то же самое, что и вы. :)
Джуто
2
awk - это стандартный инструмент UNX (т.е. доступный во ВСЕХ установках UNIX) для обработки текстовых файлов. Это то, для чего он был изобретен, и он очень хорош в этом. Если вы работаете в UNIX и анализируете текстовые файлы, изучите awk из книги Арнольда Робинса «Эффективное программирование Awk, третье издание». Есть небольшой сдвиг парадигмы, связанный с condition { action }синтаксисом awks, но тогда это проще простого для любого, кто имеет опыт работы с C или другим языком на основе Algol.
Эд Мортон
Бонус: результат примерно такой grep -Hn --color:awk '/loom/ && !/gloom/ { gsub(/loom/, color("1;31") "&" color(0)); print color(35) FILENAME color(36) ":" color(32) FNR color(36) ":" color(0) $0; }; function color(c) { return "\033[" c "m"; }'
tangle
6

-v - это флаг "перевернутого совпадения", так что конвейер - очень хороший способ:

grep "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)| grep -v "gloom"

Олег Кокорин
источник
5

/ * Вы могли бы выглядеть примерно так?

grep -vn "gloom" `grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)`

BACKQUOTES используются как скобки для команд, поэтому в этом случае при -lвключении код в BACKQUOTES вернет вам имена файлов, а затем с -vn, чтобы сделать то, что вы хотели: иметь имена файлов, номера строк, а также фактические строки.

ОБНОВЛЕНИЕ Или с помощью xargs

grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp) | xargs grep -vn "gloom"

Надеюсь, это поможет.*/

Не обращайте внимания на то, что я написал выше, это чушь.

grep -n "loom" `grep -l "loom" tt4.txt` | grep -v "gloom"

               #this part gets the filenames with "loom"
#this part gets the lines with "loom"
                                          #this part gets the linenumber,
                                          #filename and actual line
Джуто
источник
4

Вы можете использовать grep -P(регулярное выражение perl) negative lookbehind:

grep -P '(?<!g)loom\b' ~/projects/**/trunk/src/**/*.@(h|cpp)

Я добавил \bграницы слов.

анубхава
источник
2
Вам не нужно оглядываться назад, \([^g]\|^\)работает. И это не исключает строк с обоими loomи gloom.
Кевин
@Kevin: OP хочет найти линии с ткацким станком, но not gloom.
анубхава
Точно. Если в строке есть и то, и другое, он не хочет этого, но это все равно будет совпадать.
Кевин
@Kevin: Это НЕ будет соответствовать мраку, но будет соответствовать ткацкому станку (как того хочет OP).
анубхава
Из вопроса: Значит, мне нужно, например, bloombergв выводе команды, а не нужно ungloomy. Таким образом, границы слов контрпродуктивны.
Джонатан Леффлер
3
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
Чиминьон
источник
Из вопроса: Значит, мне нужно, например, bloombergв выводе команды, а не нужно ungloomy. Если бы одна строка содержала «… а bloomberg не слишком мрачен в отношении перспектив…», вы бы удалили эту строку, но она нужна (потому что if содержит bloomberg).
Джонатан Леффлер
@JonathanLeffler "Мне нужно найти все файлы / строки, включая ткацкий станок, за исключением тех, которые мрачны".
Jiminion
3

Просто используйте! grep -vмногократно.

Содержание файла

[root@server]# cat file
1
2
3
4
5

Исключить строку или совпадение

[root@server]# cat file |grep -v 3
1
2
4
5

Исключить строку или сопоставить несколько

[root@server]# cat file |grep -v 3 |grep -v 5
1
2
4
Тиборч Поцелуй
источник
0

Вопрос: ищите «ткацкий станок», исключая «мрак».
Ответ:

grep -w 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
Абхинандан
источник
1
Из вопроса: Значит, мне нужно, например, bloombergв выводе команды, а не нужно ungloomy. Я не думаю, что -wэто решение этой головоломки.
Джонатан Леффлер