Греп-регекс НЕ містить рядок


181

Я передаю список зразків регулярних виразів, grepщоб перевірити наявність файлу syslog. Зазвичай вони відповідають IP-адресі та запису журналу;

grep "1\.2\.3\.4.*Has exploded" syslog.log

Це просто список шаблонів, як "1\.2\.3\.4.*Has exploded"частина, яку я проходжу, в циклі, тому я не можу, наприклад, пропустити "-v".

Я розгублений, намагаючись зробити зворотне вищезазначене, НЕ збігаються рядки з певною IP-адресою та помилкою, так що "! 1.2.3.4. * Вибухнуло" буде відповідати рядкам syslog для будь-якого іншого, ніж 1.2.3.4, що говорить про те, що він вибухнув . Я повинен бути в змозі включити IP, щоб НЕ збігався.

Я бачив різні подібні дописи на StackOverflor, однак вони використовують схеми регулярних виразів, з якими я не можу працювати grep. Чи може хтось надати робочий приклад, grepбудь ласка?

ОНОВЛЕННЯ: Це відбувається в такому сценарії;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done

Ви маєте на увазі, що іноді хочете відповідати шаблону, але в інших випадках хочете відповідати всім, крім певного шаблону? (це здається дивним вимогою, але як би там не було). У такому випадку, чому б вам не повторити два різних списки шаблонів?
beerbajay

Ну, я не дуже обізнаний у регексе; Я не хочу поздоровлятись за "Вибухнув", тому що я не хочу знати це про кожен пристрій реєстрації, тому я можу якось простувати за "Вибухнув" та! 9.10.11.12 в одному виписці?
jwbensley

Якщо ви абсолютно повинні це зробити в одному висловлюванні, негативний погляд ззаду - це шлях, як пропонує Ніл. Дивіться мій коментар там.
пивабая

Використовуйте відповідність регулярного виразів у стилі PCRE та негативне твердження пошуку, відповідно до відповіді @Neil: patterns[3]="\!9\.10\.11\.12.*Has exploded"зміни patterns[3]="(?<!9\.10\.11\.12).*Has exploded"та grep "${patterns[$i]}" logfile.logзміни на grep -P "${patterns[$i]}" logfile.logPCRE передбачають більше метахарактерів за замовчуванням, тому деякі шляхи, можливо, потрібно буде видалити з інших відповідних виразів.
Codex24

Відповіді:


341

grepвідповідає, grep -vробить зворотне. Якщо вам потрібно "відповідати A, але не B", ви зазвичай використовуєте труби:

grep "${PATT}" file | grep -v "${NOTPATT}"

Як я вже згадував, це переходить в середину циклу, і я просто передаю PATTERN для вимкнення, щоб я не міг використовувати "-v", як я вже згадував. Я просто перебираю список PATTERN і переходжу до grep.
jwbensley

1
Ви дійсно можете використовувати, -vі ви можете використовувати його в циклі. Можливо, вам потрібно бути більш конкретними щодо ваших обмежень, або, можливо, у вас є помилкове уявлення про те, як повинен працювати ваш сценарій. Спробуйте опублікувати якийсь код.
beerbajay

Дякую beerbajay, я додав код, фрагмент до оригінальної публікації, щоб дати деякий контекст. Ви бачите, що я маю на увазі зараз?
jwbensley

Ця відповідь не зовсім коректна, але ви дуже багато пишете beerbajay, мені потрібно було переосмислити цикл і використати -v врешті-решт. Дякую за вказівник;)
jwbensley

1
Але що робити, якщо A складається з B? Іншими словами, що робити, якщо я хочу відповідати лінії без A і лінії з AB? Труба не буде працювати.
pawamoy

15
(?<!1\.2\.3\.4).*Has exploded

Вам потрібно запустити це з -P, щоб мати негативний вигляд (регулярний вираз Perl), тому команда така:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

Спробуйте це. Він використовує негативний погляд позаду, щоб ігнорувати рядок, якщо до цього звертається 1.2.3.4. Сподіваюся, що це допомагає!


1
Я впевнений, що grepце не підтримує пошук. Якщо ви не використовуєте Gnu grepі не використовуєте --Pпараметр, щоб він використовував движок PCRE.
Тім Піцкер

Ні, grep не підтримує цей тип Regex; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: помилка синтаксису біля несподіваного маркера `('
jwbensley

Вам потрібно буде цитувати регулярний вираз, якщо він містить символи, які будуть інтерпретовані оболонкою.
beerbajay

правильне цитування: grep -P '(?<!1\.2\.3\.4) Has exploded' test.logЗверніть увагу, що огляд за спиною працює лише на символи, що безпосередньо передують збіжній частині виразу, тому якщо між адресою та повідомленням є інші речі, наприклад 1.2.3.4 FOO Has exploded, це не спрацює.
beerbajay

@TimPietzcker, дуже спостережливий. Я додам це до питання. Крім того, зауважте, що .*позаду є негативний погляд, оскільки його приклад також є, я думаю, що між ними може бути інший текст.
Ніл

2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

повинні бути такими ж, як

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.