Я пытаюсь найти все экземпляры, за Ui\.
которыми не следует Line
или даже просто букваL
Как правильно написать регулярное выражение для поиска всех экземпляров определенной строки, за которой НЕ следует другая строка?
Использование опережающих просмотров
grep "Ui\.(?!L)" *
bash: !L: event not found
grep "Ui\.(?!(Line))" *
nothing
regex
grep
regex-lookarounds
Ли Куарелла
источник
источник
set +o histexpand
в Bash илиset +H
YMMV.Ответы:
Отрицательный просмотр вперед, который вам нужен, требует более мощного инструмента, чем стандартный
grep
. Вам понадобится grep с поддержкой PCRE.Если у вас есть GNU
grep
, текущая версия поддерживает параметры-P
или,--perl-regexp
после чего вы можете использовать желаемое регулярное выражение.Если у вас нет (достаточно последней версии) GNU
grep
, подумайте о приобретенииack
.источник
!
как специальный символ.-P
не поддерживается TRY результат трубопровода сноваgrep --invert-match
, исключая:git log --diff-filter=D --summary | grep -E 'delete.*? src' | grep -E --invert-match 'xml'
. Не забудьте проголосовать за ответ @Vinicius Ottoni.Ответ на часть вашей проблемы здесь, и ack будет вести себя таким же образом: Ack и отрицательный просмотр вперед дают ошибки
Вы используете двойные кавычки для grep, что позволяет bash «интерпретировать
!
как команду раскрытия истории».Вам нужно обернуть свой узор в ОДИНОЧНЫЕ ЦИТАТЫ:
grep 'Ui\.(?!L)' *
Однако см . Ответ @JonathanLeffler, чтобы решить проблемы с негативным прогнозом в стандартном исполнении
grep
!источник
grep
с функциональностью стандартаgrep
, где стандартомgrep
является POSIX. То, что вы говорите, также верно - я запускаю Bash с отключенными варварствами C-оболочки (потому что, если бы я хотел оболочку C, я бы использовал ее, но я не хочу ее), поэтому на!
меня это не влияет - но чтобы получить негативный взгляд вперед, нужен нестандартныйgrep
.Вы, вероятно, не можете выполнить стандартный отрицательный просмотр вперед с помощью grep, но обычно вы можете получить эквивалентное поведение, используя «обратный» переключатель '-v'. Используя это, вы можете создать регулярное выражение для дополнения того, что вы хотите сопоставить, а затем передать его через 2 greps.
Для рассматриваемого регулярного выражения вы можете сделать что-то вроде
источник
Если вам нужно использовать реализацию регулярного выражения, которая не поддерживает отрицательный просмотр вперед, и вы не возражаете против сопоставления дополнительных символов *, тогда вы можете использовать классы отрицательных символов
[^L]
, чередование|
и привязку конца строки$
.В вашем случае
grep 'Ui\.\([^L]\|$\)' *
делает свою работу.Ui\.
совпадает с интересующей вас строкой\([^L]\|$\)
соответствует любому одиночному символу, кромеL
или соответствует концу строки:[^L]
или$
.Если вы хотите исключить более одного символа, вам просто нужно добавить к нему больше чередования и отрицания. Найти
a
не следуетbc
:grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *
Что либо (
a
за которым следует notb
или за которым следует конец строки:a
then[^b]
или$
), либо (a
заb
которым следует либо not,c
либо следует конец строки:a
thenb
, then[^c]
или$
.Такое выражение становится довольно громоздким и подверженным ошибкам даже с короткой строкой. Вы могли бы написать что-нибудь для генерации выражений для вас, но, вероятно, было бы проще просто использовать реализацию регулярного выражения, которая поддерживает отрицательный просмотр вперед.
* Если ваша реализация поддерживает группы без захвата, вы можете избежать захвата дополнительных символов.
источник
Если ваш grep не поддерживает -P или --perl-regexp, и вы можете установить grep с поддержкой PCRE, например, "pcregrep", то ему не потребуются какие-либо параметры командной строки, такие как GNU grep, для принятия Perl-совместимого обычного выражения, вы просто бежите
Вам не нужна другая вложенная группа для «Line», как в вашем примере «Ui. (?! (Line))» - достаточно внешней группы, как я показал выше.
Позвольте мне привести вам еще один пример поиска отрицательных утверждений: когда у вас есть список строк, возвращенный "ipset", каждая строка показывает количество пакетов в середине строки, и вам не нужны строки с нулевыми пакетами, вы просто бегать:
Если вам нравятся регулярные выражения, совместимые с perl, и у вас есть perl, но у вас нет pcregrep, или ваш grep не поддерживает --perl-regexp, вы можете использовать однострочные сценарии Perl, которые работают так же, как grep:
Perl принимает stdin так же, как grep, например
источник