Почему в моем выражении grep необходимо использовать $'string' для сопоставления символов табуляции?

Почему в моем выражении grep необходимо использовать $'string' для сопоставления символов табуляции?

Если взять этот код:

echo -e '\t\t\tString' | grep '^[\t]*String'

результат пустой, потому что он не совпадает, однако это:

echo -e '\t\t\tString' | grep $'^[\t]*String'

работает. Клянусь, я, должно быть, использовал код первой строки сотню раз в своих скриптах и ​​в терминале, никогда не используя символ "$" таким образом, и это всегда работало. Были ли какие-то недавние изменения? Зачем нужен символ "$"? Или я что-то делаю не так?

решение1

Котировка ANSI-C

Согласно руководству Bash, это называетсяANSI-C цитирование. В руководстве говорится:

Слова формы$'строка'обрабатываются особым образом. Слово расширяется до строки, в которой символы, экранированные обратной косой чертой, заменяются, как указано в стандарте ANSI C.

На практике это означает, что '\t'не будет расширено до символа табуляции, но $'\t'будет. Вывод должен быть эквивалентен использованию echo -e, но может использоваться везде, где вы используете строку, без необходимостизамена команды.

Такие утилиты, как GNU sed, выполняют собственное расширение экранированных символов, но GNU grep этого не делает. Оболочка Bash, а не grep, расширяет экранированные символы в строках ANSI-C в кавычках. Без ANSI-C в регулярном выражении, которое вы разместили, нет символов табуляции, соответствующих вводу.

решение2

Вероятно, вы должны понимать, что нет единого типа регулярных выражений. Есть как минимум basic regular expressionsили BRE(иногда только RE), extended regular expressionsили EREи perl compatible regular expressionsили PCRE. Все эти языки используют немного разный синтаксис. Текущие версии GNU grepподдерживают все три и BREявляются по умолчанию. Для EREвам нужно использовать -Eoption и for PCRE -Poption. Ваш пример будет работать только с , -Pтак как с базовыми и расширенными RE обратная косая черта теряет свое значение и [\t]соответствует либо обратной косой черте, либо символу t. Вероятно, вы использовали этот шаблон в каком-то другом языке, который поддерживает PCREпо умолчанию, что имеет смысл, так как они являются самой мощной версией. Или, возможно, у вас alias grep='grep -P'где-то было.

решение3

Первая строка работает, если убрать ^. Может, она работала, но не так, как вы предполагали? Сомневаюсь, что grepповедение изменилось в таком важном месте.

echoне транслирует escape-последовательности по умолчанию. -eДля этого вам нужен. Аналогично с оболочкой. Вам нужно $'...'заставить оболочку использовать escape-последовательности.

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