Подтвердить что ты не робот

Bash: простой способ передать "сырую" строку в grep?

grep нельзя использовать "сырые" строки при использовании из командной строки, так как некоторые символы должны быть экранированы, чтобы не обрабатываться как литералы. Например:

$ grep '(hello|bye)' # WON'T MATCH 'hello'
$ grep '\(hello\|bye\)' # GOOD, BUT QUICKLY BECOMES UNREADABLE

Я использовал printf для строк с автоматическим удалением:

$ printf '%q' '(some|group)\n'
\(some\|group\)\\n

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

$ grep `printf '%q' '(a|b|c)'`

Однако это явно не предназначено для этого: некоторые символы на выходе не экранированы, а некоторые - излишне. Например:

$ printf '%q' '(^#)'
\(\^#\)

Символ ^ не должен быть экранирован при передаче в grep.

Есть ли инструмент cli, который берет необработанную строку и возвращает a bash -безовую версию строки, которая может быть непосредственно использована как шаблон с grep? Как я могу достичь этого в чистом bash, если не?

4b9b3361

Ответ 1

Если вы пытаетесь получить grep для использования синтаксиса Extended Regular Expression, способ сделать это - использовать grep -E (aka egrep). Вы также должны знать о grep -F (aka fgrep) и в новых версиях GNU Coreutils grep -P.

Фон: исходный grep имел довольно небольшой набор операторов регулярных выражений; это была оригинальная реализация регулярного выражения Кен Томпсона. Новая версия с расширенным репертуаром была разработана позже, а по соображениям совместимости - другое имя. С GNU grep существует только один двоичный код, который понимает традиционный базовый синтаксис RE, если он вызван как grep, и ERE, если он вызван как egrep. Некоторые конструкции из egrep доступны в grep с помощью обратного слэша, чтобы ввести специальный смысл.

Впоследствии язык программирования Perl еще больше расширил формализм; этот диалект регулярного выражения, по-видимому, является тем, что большинство новичков ошибочно ожидают поддержки grep. С grep -P он делает это; но это еще не широко поддерживается на всех платформах.

Итак, в grep следующие символы имеют особое значение: ^$[]*.\

В egrep следующие символы также имеют особое значение: ()|+?{}. (Скобки для повторения не были в оригинале egrep.) Скобки для группировки также позволяют обратные ссылки с помощью \1, \2 и т.д.

Во многих версиях grep вы можете получить поведение egrep, поставив обратную косую черту перед специальными предложениями egrep. Существуют также специальные последовательности, такие как \<\>.

В Perl было введено огромное количество дополнительных экранов, таких как \w \s \d. В Perl 5 средство регулярного выражения было существенно расширено, с нежелательным соответствием *? +? и т.д., Негрупповыми скобками (?:...), lookaheads, lookbehinds и т.д.

... Сказав это, если вы действительно хотите преобразовать регулярные выражения egrep в регулярные выражения grep без вызова какого-либо внешнего процесса, попробуйте ${regex/pattern/substitution} для каждого из специальных символов egrep; но признайте, что это не обрабатывает классы символов, отрицательные классы символов или правильные обратные следы.

Ответ 2

Если вы хотите найти точную строку,

grep -F '(some|group)\n' ...

-F сообщает grep обрабатывать шаблон как есть, без интерпретации в качестве регулярного выражения.

(Это часто доступно как fgrep.)

Ответ 3

Когда я использую grep -E с предоставленными пользователем строками, я убегаю их с этим

ere_quote() {
    sed 's/[]\.|$(){}?+*^]/\\&/g' <<< "$*"
}

пример run

ere_quote ' \ $ [ ] ( ) { } | ^ . ? + *'
# output
# \\ \$ \[ \] \( \) \{ \} \| \^ \. \? \+ \*

Таким образом, вы можете безопасно вставлять строку с кавычками в свое регулярное выражение.

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

userdata=".*"
grep -E "^$(ere_quote "$userdata")" <<< ".*hello"
# if you have colors in grep you'll see only ".*" in red

Ответ 4

Я думаю, что предыдущие ответы не полны, потому что они пропускают одну важную вещь, а именно строку, начинающуюся с тире (-). Поэтому, пока этот не будет работать:

echo "A-B-C" | grep -F "-B-"

Это будет:

echo "A-B-C" | grep -F -- "-B-"