Экранирование регулярного выражения для grep в bash

Каков наилучший способ преобразовать регулярное выражение в строку, которая может быть принята grep/sed в bash?

например, с учетом следующего регулярного выражения

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

bash это не нравится (поэтому это регулярное выражение нельзя использовать в grep)

$ echo "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"
-bash: syntax error near unexpected token `('

$ echo '(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])'
>
> ^C

Я предполагаю, что регулярное выражение нужно экранировать, но я не нашел хорошего инструмента, который мог бы сделать это за меня.

есть идеи, как я могу позволить grep использовать это регулярное выражение в bash?

Если я не ошибаюсь, вы пытаетесь использовать это регулярное выражение для захвата электронных писем. В этом аспекте вы можете использовать grep -E -o "your regex here" file.txt - Также ознакомьтесь с этим постом: stackoverflow.com/questions/2898463/…

George Vasiliou 19.06.2023 14:16

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

Verpous 19.06.2023 14:16

@GeorgeVasiliou, как видите, я не могу заключать регулярное выражение в двойные\одинарные кавычки. поэтому я открываю кейс. интересно как это можно сделать :)

Mr. 19.06.2023 14:41

@Verpous Я знаю, что это нужно сбежать, это то, что я написал. Мне нужна команда\инструмент, который сделает это за меня без участия человека.

Mr. 19.06.2023 14:41

@Мистер. Откуда тогда приходит регулярное выражение и как вы собираетесь его использовать? Можете ли вы отредактировать свой пост с более конкретным примером вашего варианта использования, который иллюстрирует это?

Verpous 19.06.2023 17:34
В чем разница между методом "==" и equals()
В чем разница между методом "==" и equals()
Это один из наиболее часто задаваемых вопросов новичкам на собеседовании. Давайте обсудим его на примере.
Замена символа по определенному индексу в JavaScript
Замена символа по определенному индексу в JavaScript
В JavaScript существует несколько способов заменить символ в строке по определенному индексу.
1
5
54
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

С моей mquote (волшебная цитата):

$ mquote (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
>>> '(?:[a-z0-9!#$%&'\''*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'\''*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])'
Ответ принят как подходящий

Давайте объединим две полезные функции Bash, чтобы добиться этого.

Во-первых, вы можете полностью избежать необходимости экранировать строку, используя документ Here Doc с разделителем в кавычках (например, <<"separator"). Например, вы можете написать что-то вроде этого:

cat<<"EOF"
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
EOF

Во-вторых, обернув этот документ Here Doc в функцию, вы можете легко перенести его в переменную. С этого момента вы можете напрямую предоставить эту переменную для grep или sed.

Например:

function regex() {
cat<<"EOF"
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
EOF
}

echo "[email protected]" | grep -P $( regex )

Обратите внимание, что для вашего регулярного выражения требуется механизм регулярных выражений, совместимый с Perl (также известный как PCRE). Экранированные шестнадцатеричные последовательности внутри выражений классов символов (например, [\x70-\x7f]) не поддерживаются большинством других движков, что означает, что предыдущая последовательность будет соответствовать этим символам: \, x, 7, 0-\, x, 7, f).

возможно, он экранирует строку, но влияет на регулярное выражение, и поэтому регулярное выражение не фиксирует какой-либо адрес электронной почты.

Mr. 19.06.2023 15:07

Действительно. Я изменил объяснение того, как использовать регулярное выражение напрямую с egrep, без части printf '%q'.

James 19.06.2023 15:50

Единственное, что вам нужно знать, это как заключить строку с одним кавычки, если строка содержит одинарные кавычки внутри. Позвольте мне упростить строку в качестве примера:

O'Reilly

Как вы знаете, обратная косая черта не работает, чтобы избежать одинарной кавычки внутри одинарных кавычек:

str='O\'Reilly'         # wrong

Вместо этого вы можете сказать:

str='O'\''Reilly'

Это может показаться странным, но это просто конкатенация 'O', \' и 'Reilly'.

'O'      ... single quoted string "O"
\'       ... literal single quote
'Reilly' ... single quoted string "Reilly"

Затем вы можете назначить переменную своему регулярному выражению с помощью:

regex='(?:[a-z0-9!#$%&'\''*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'\''*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])'

# echo "$regex"

grep -P "$regex" <<< '[email protected]'

Обратите внимание, что две одинарные кавычки обрабатываются так же, как в приведенном выше примере.

Другие вопросы по теме