Linux grep с вопросом о регулярном выражении

Я пробую приведенный ниже код и надеюсь получить результат как 0 (т.е. $? -Eq 0 ), но по какой-то причине это всегда терпит неудачу:

echo "INBOUND_PATH | / tmp "| grep -E '^ \ (INBOUND_PATH \) \ | \ (. * \) $';

echo $?

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

g_inboundDir = grep -E 's / ^ \ (INBOUND_PATH \) \ | (. *) $ / \ 2';

0
10.07.2017, 02:34
3 ответа

Объединив пробел и собрав все ответы вместе, а также взглянув на справочную страницу grep (man grep), мы видим два основных типа регулярных выражений :Basic Regex и Extended Regex.

Согласно man grep:

Basic vs Extended Regular Expressions
In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions \?, +, {, \|, (,and ).

Другими словами, вы можете захватывать группы с помощью одного grep, используя escape-последовательность (), например grep \(....\), или если вы используете grep -Eили egrep, вам не нужно экранировать круглые скобки:egrep '(....)'

К sed применяются те же правила. Простой sed понимает основные регулярные выражения, поэтому вам нужно экранировать для захвата групп:sed 's/\(....\)\(...\)/\2/'или вы можете включить расширенную поддержку регулярных выражений в sedс помощью переключателя -Eили -r(в зависимости от реализации sed):sed -E 's/(...)(...)/\2/'

В результате все приведенные ниже команды действительны:

$ echo "INBOUND_PATH|/tmp" | grep '^\(INBOUND_PATH\)|\(.*\)$';echo $?
INBOUND_PATH|/tmp
0

$ echo "INBOUND_PATH|/tmp" | egrep '(INBOUND_PATH)\|(.*)$';echo $?
INBOUND_PATH|/tmp
0

$ echo "INBOUND_PATH|/tmp" | sed 's/^\(INBOUND_PATH\)|\(.*$\)/\2/'
/tmp

$ echo "INBOUND_PATH|/tmp" | sed -E 's/(INBOUND_PATH)\|(.*)$/\2/'
/tmp

Обратите внимание на противоположную обработку специальных символов в разных регулярных выражениях.

Например, см. обработку символа трубы |в приведенных выше командах:
В базовом регулярном выражении (BRE):
Вам не нужно экранировать символ трубы, чтобы соответствовать буквальному символу трубы.
Экранирующий символ вертикальной черты в BRE будет рассматриваться как оператор ИЛИ (, который случайно сработает в вашем случае ).

Аналогично, в BRE вам не нужно экранировать круглые скобки ( ), чтобы соответствовать буквальным скобкам, но вам нужно экранировать круглые скобки, чтобы захватить группу.

В расширенном регулярном выражении (ERE):
Вам нужно экранировать символ трубы, чтобы сопоставляться буквально, поскольку по умолчанию в ERE символ трубы обрабатывается как оператор ИЛИ (, противоположная обработка по сравнению с BRE)

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

1
28.01.2020, 02:45

Базовая проверка строки не должна быть такой уж сложной:
echo "INBOUND_PATH|/tmp" | grep -q '^INBOUND_PATH|.*$'

Я полагаю, вы имели в виду, что второй должен быть sed, а не grep:
g_inboundDir=$(echo "INBOUND_PATH|/tmp" | sed 's/^\(INBOUND_PATH\)|\(.*$\)/\2/')

Обратите внимание на отсутствие -E. Я также исправил отсутствующий трейлинг /.

0
28.01.2020, 02:45

Вы добавляете -E, которое является расширенным регулярным выражением

-E, --extended-regexp Interpret PATTERN as an extended regular expression (ERE, see below).

И все еще избегая этого. В этом нет необходимости.

$ echo "INBOUND_PATH|/tmp" | grep -E '^(INBOUND_PATH)\|(\/.*)'; echo $?
INBOUND_PATH|/tmp
0

С другой стороны, вы можете использовать egrep с тем же эффектом (без -E ).

0
28.01.2020, 02:45

Теги

Похожие вопросы