grep для "терміна" та виключити "інший термін"


28

Я намагаюся створити греп-пошук, який шукає термін, але виключає рядки, які мають другий термін. Я хотів використовувати кілька -e "pattern"варіантів, але це не спрацювало.

Ось приклад команди, яку я спробував, і повідомлення про помилку, яке вона створила.

grep -i -E "search term" -ev "exclude term"
grep: exclude term: No such file or directory

Мені здається, що це -vстосується всіх пошукових термінів / моделей. Оскільки це працює, але потім не включає search termрезультати.

grep -i -E "search term" -ve "exclude term"

Чи є якийсь інший варіант виключення, оскільки іноді доводиться стискати рядки навколо слова, і якщо ми виключаємо в наступній операції, використовуючи '|' , воно просто видаляє це слово, але не видаляє блок для цього слова
Учень

Відповіді:


40

Для та виразів з grep вам потрібно два виклики:

grep -Ei "search term" | grep -Eiv "exclude term"

Якщо пошукові терміни не є регулярними виразами, використовуйте фіксовану відповідність рядків ( -F), яка швидше:

grep -F "search term" | grep -Fv "exclude term"

18

Незважаючи на те, що двічі викликати греп, є лише один із способів придумати це. Вона включає в себе Perl Compatible Regular Expressions (PCRE) і деякі досить Hacky Оглядітися затвердження .

Для пошуку foo, за винятком збігів, що містять смугу , ви можете використовувати:

grep -P '(?=^((?!bar).)*$)foo'

Ось як це працює:

  • (?!bar)відповідає будь-якому, що не заборонено, не використовуючи символи з рядка. Потім .споживає один символ.

  • ^((?!bar).)*повторює вище сказане від початку рядка ( ^) до кінця його ( $). Він не вдасться, якщо barйого зустрінуть у будь-якій точці, оскільки (?!bar)не збігаються.

  • (?=^((?!bar).)*$) гарантує, що рядок відповідає попередньому шаблону, не споживаючи символів з рядка.

  • fooшукає foo як завжди.

Я знайшов цей хак в регулярному виразі, щоб він відповідав рядку, що не містить слова? . У відповіді Барта Кірса ви можете знайти набагато більш детальне пояснення того, як діє негативний погляд вперед.


Гарний хак. Цей трюк працює і в Java, btw.
Раман

12

Якщо ви хочете зробити це за один прохід, ви можете використовувати awk замість grep.

Формат:

echo "some text" | awk '/pattern to match/ && !/pattern to exclude/'

Приклади:

  • echo "hello there" | awk '/hello/ && !/there/'

Повертає нічого.

  • echo "hello thre" | awk '/hello/ && !/there/'

Повертається: привіт кинув

  • echo "hllo there" | awk '/hello/ && !/there/'

Повертає нічого.

Для декількох шаблонів ви можете використовувати дужки, щоб згрупувати їх.

Приклади:

  • echo "hello thre" | awk '(/hello/ || /hi/) && !/there/'

Повертається: привіт кинув

  • echo "hi thre" | awk '(/hello/ || /hi/) && !/there/'

Повертається: привіт

  • echo "hello there" | awk '(/hello/ || /hi/) && !/there/'

Повертає нічого.

  • echo "hi there" | awk '(/hello/ || /hi/) && !/there/'

Повертає нічого.


1
Це працювало для мене, але я втратив кольори = P
Леопольдо Санчик

1
Кольори з якого виходу? Якщо ви намагаєтеся зберегти кольори за допомогою ls, використовуйте аргумент "--color = always" під час розбору виводу (інакше ви завжди втрачаєте кольори під час розбору тексту). Приклад: ls --color=always | awk '/hello/ && !/goodbye/'
Філіп Різ

Дякую за відповідь @Philip! Я пробував це раніше, але без успіху. Я думаю, що як візерунок має кольоровий текст, він не збігається пізніше, і я повинен включити якийсь колірний код до шаблону. У будь-якому випадку, ваш - це найшвидший спосіб, який я знайшов зробити grep -Rу кількох файлах коду за допомогою командного рядка Ubuntu.
Леопольдо Санчік

1

З моїх експериментів це не має великого значення, якщо ви передаєте свої умови виключення через grepабо sed. Sed має деякі корисні функції заміни тексту, які я часто використовую для кращого фільтрування файлів журналів. Тому я збираюся використовувати sed, оскільки я комбіную досить багато фільтрів на sed.

wc /var/log/tomcat/tomcat.2013-01-14.log.1 
  1851725

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/ вхід ОК / d" -e "/ Термін дії закінчився / d" | туалет
24.05користувач 0.15система 0: 25.27затримка 95% ЦП (0avgtext + 0avgdata 3504макс. Резидент) k
0введення + 0 вихідні (0major + 246minor) параметри сторінок 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/ вхід ОК / d" -e "/ Термін дії закінчився / d" | туалет
23.50користувач 0.16система 0: 24,48елемент 96% ЦП (0avgtext + 0avgdata 3504макс. Резидент) k
0введення + 0 вихідні (0major + 246minor) параметри сторінок 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "вхід ОК" -e "Термін дії закінчився" | туалет
23.08 користувач 0.14система 0: 23,55елемент 98% ЦП (0avgtext + 0avgdata 3504макс. Резидент) k
0введення + 0 вихідні (0major + 246minor) параметри сторінок 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "вхід ОК" -e "Термін дії закінчився" | туалет
23.50користувач 0.15система 0: 25,27затримка 93% ЦП (0avgtext + 0avgdata 3488maxresident) k
0введення + 0 вихідні (0майорів + 245хвилин) параметри сторінок 0зміни
   5614 91168 1186298


3
Спробуйте порівняти час виконання grep -Fзамістьgrep -E а не використовувати його, -iякщо він вам не потрібен.
Тор

1
Але тоді ви не наводите приклади, використовуючи sed;)
Бенджамін R
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.