Результат регулярного выражения Grep не соответствует ожидаемому?

Результат регулярного выражения Grep не соответствует ожидаемому?

Использование FreeBSD 11.1:

#!/bin/sh

if printf 'abcde.fgh' | grep -iEq '^[^][$^*_-]'; then
    echo "test 1 success"
else
    echo "test 1 fail"
fi

echo

if printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'; then
    echo "test 2 success"
else
    echo "test 2 fail"
fi

Выход:

test 1 success

grep: Unmatched [ or [^
test 2 fail

Но AFAICT они должны давать тот же результат. Они оба содержат условие на первый символ (только), что он не входит в список указанных неалфавитных символов. Разбивка регулярного выражения:

  • ^= начало строки
  • [^...]= совпадение, если ни один из этих символов не соответствует
  • В списке ]должен быть первым символом, ^не должен быть первым, и - должен быть последним. Таков ][.^$_-допустимый список литеральных символов, и строка не должна совпадать ни с одним из них.
  • Во избежание путаницы следует отметить, что это означает, что в списке ][присутствуют литералы "]"и символы,"["нетзакрытие и повторное открытие 2 списков.

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

Что я упускаю? Наверное, что-то очень очевидное и простое?

решение1

Вы упускаете несколько других правил синтаксиса. В расширении скобок, в дополнение к простым диапазонам, есть также несколько типов многосимвольных выражений, которые начинаются с [. (См.регулярное выражение(7)руководство дляЛинуксилиFreeBSDв "За исключением этихи некоторые комбинации с использованием '['(см. следующие параграфы)".) Это:

  • Элементы подбора: [..]
  • Классы эквивалентности: [==]
  • Классы персонажей: [::]

(Вы могли видеть или использовать такие выражения, как [[:digit:]]– на самом деле это класс символов [:digit:], который является единственным элементом […]раскрытия скобок.)

Так что в вашем случае, поскольку .находится сразу после a [, они распознаются как открывающий разделитель элемента сортировки. GNU grep 3.1 выдает правильное сообщение об ошибке:

$ printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'
grep: Unmatched [, [^, [:, [., or [=

Те же выражения можно использовать для выхода из подобных ситуаций, используя, например, [...]или [=.=]для включения обычной точки, или аналогичным образом [=-=]для сопоставления с тире, если их некуда переместить.

Связанный контент