2012-02-08 4 views
73

Я пытающийся Grep для всех экземпляров Ui\. не следует Line или даже просто письма LRegex предпросмотр для «не» в Grep

Что такое правильный способ, чтобы написать регулярное выражение для нахождения всех экземпляров конкретной строки NOT, за которой следует другая строка?

Использование lookaheads

grep "Ui\.(?!L)" * 
bash: !L: event not found 


grep "Ui\.(?!(Line))" * 
nothing 
+3

Какие подвид регулярного выражения - PCRE, ERE, BRE, grep, ed, sed, perl, python, Java, C, ...? –

+0

Использование его с grep. –

+4

Как в стороне, «событие не найдено» происходит от использования расширения истории. Возможно, вы захотите отключить расширение истории, если вы никогда не используете его, а иногда хотите использовать восклицательный знак в своих интерактивных командах. 'set + o histexpand' в Bash или' set + H', YMMV. – tripleee

ответ

104

отрицательный предпросмотр, который является то, что вы 're after, требуется более мощный инструмент, чем стандартный grep. Вам понадобится grep с поддержкой PCRE.

Если у вас есть GNU grep, текущая версия поддерживает опции -P или --perl-regexp, и вы можете использовать нужное вам регулярное выражение.

Если у вас нет (достаточно последняя версия) GNU grep, рассмотрите вопрос о получении ack.

+29

Я уверен, что проблема в этом случае заключается только в том, что в bash вы должны использовать одинарные кавычки, а не двойные кавычки, чтобы он не рассматривал '!' Как специальный символ. – NHDaly

+0

(см. Ниже мой ответ, описывающий именно это.) – NHDaly

+1

Проверенный, правильный ответ должен сочетать этот ответ и комментарий @ NHDaly. Например, эта команда работает для меня: ** grep -P '^. * Содержит ((?! But_not_this).) * $' \ *. Log. *> "D: \ temp \ result.out "** – wangf

1

Я думаю, что эта связь может помочь вам, во-первых, чтобы понять, как регулярное выражение работает и второй, как построить свой регулярное выражение: http://www.regular-expressions.info/tutorialcnt.html

30

Ответ на часть вашей проблемы здесь, и извед будет вести себя так же, как: «интерпретируют ! как история команды расширения» Ack & negative lookahead giving errors

Вы используете двойные кавычки для Grep, которая позволяет Баш на

Вам нужно обернуть шаблон в апострофах: grep 'Ui\.(?!L)' *

Однако увидеть @JonathanLeffler's answer для решения проблем с отрицательным lookaheads в стандартном grep!

+0

Вы смешиваете функциональность расширения GNU' grep' с функциональностью стандартного 'grep', где стандарт для' 'grep' '(http://pubs.opengroup.org)/onlinepubs/9699919799/utilit ies/grep.html) является POSIX. То, что вы говорите, также верно - я запускаю Bash с отключенными barbarisms C-shell (потому что, если мне нужна оболочка C, я бы использовал ее, но я не хочу ее), поэтому '!' Stuff does not влияют на меня - но чтобы получить негативные взгляды, вам нужен нестандартный 'grep'. –

+0

@ JonathanLeffler, спасибо за разъяснение; Я думаю, вы правы, что для этого нужны оба наших ответа, чтобы рассмотреть все симптомы OP. Благодарю. – NHDaly

4

Возможно, вы не можете выполнять стандартные негативные образы с помощью grep, но обычно вы должны иметь возможность получить эквивалентное поведение с помощью «инверсного» переключателя «-v». Используя это, вы можете создать регулярное выражение для дополнения того, что вы хотите сопоставить, а затем передать его через 2 greps.

Для регулярных выражений в вопрос, который вы могли бы сделать что-то вроде

grep 'Ui\.' * | grep -v 'Ui\.L' 
+0

Это исключало бы больше вещей, больше примеров, если строка содержит Ui.Line и Ui без .Line – nafg

+0

(Да, поэтому я не формулирую ее строго. Это просто решает значительную часть сценариев, которые перемещают людей к этой проблеме, ничего Больше.) –

3

Если вам нужно использовать реализацию регулярных выражений, который не поддерживает негативные lookaheads и вы не возражаете соответствие дополнительный символ (ы) *, то вы можете использовать negated character classes [^L], alternation | и end of string anchor $.

В вашем случае grep 'Ui\.\([^L]\|$\)' * выполняет эту работу.

  • Ui\. соответствует строке вы заинтересованы в

  • \([^L]\|$\) соответствует любому символу, кроме L или совпадает с концом строки: [^L] или $.

Если вы хотите исключить больше одного символа, вам просто нужно бросить на него больше чередования и отрицания. Чтобы найти a не следует bc:

grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *

Какой либо (a следуют не b или после конца строки: a затем [^b] или $) или (a с последующим b, который либо а затем не c или сопровождается конца строки:. затем ab, то [^c] или $

Этот вид выражения становится довольно громоздким и подвержен ошибкам с короткой строкой. Вы могли бы написать что-то, чтобы сгенерировать выражения для вас, но, вероятно, было бы проще просто использовать реализацию регулярного выражения, которая поддерживает негативные образы.

* Если ваша реализация поддерживает non-capturing groups, вы можете избежать захвата дополнительных символов.

0

Если ваш grep не поддерживает -P или -perl-regexp, и вы можете установить grep с поддержкой PCRE, например. «Pcregrep», чем не будет нуждаться в каких-либо параметров командной строки, такие как GNU Grep принять Perl-совместимые регулярные выражения, вы просто запустите

pcregrep "Ui\.(?!Line)" 

Вам не нужна еще одна вложенная группа для «линии», как и в ваш пример «Ui. (?! (Line))» - внешняя группа достаточна, как показано выше.

Позвольте мне привести еще один пример ожидающих отрицательных утверждений: когда у вас есть список строк, возвращаемых «ipset», каждая строка показывает количество пакетов в середине строки и вам не нужны строки с нулем пакеты, просто запустите:

ipset list | pcregrep "packets(?! 0)" 

Если вам нравится Perl-совместимых регулярных выражений и имеют Perl, но не имеют pcregrep или ваш Grep не поддерживает --perl-регулярное выражение, вы можете вы одна линия Perl скрипты, которые работают так же, как grep:

perl -e "while (<>) {if (/Ui\.(?!Lines)/){print;};}" 

Perl принимает stdi n аналогично grep, например.

ipset list | perl -e "while (<>) {if (/packets(?! 0)/){print;};}" 
Смежные вопросы