
Если взять этот код:
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
вам нужно использовать -E
option и for PCRE
-P
option. Ваш пример будет работать только с , -P
так как с базовыми и расширенными RE обратная косая черта теряет свое значение и [\t]
соответствует либо обратной косой черте, либо символу t. Вероятно, вы использовали этот шаблон в каком-то другом языке, который поддерживает PCRE
по умолчанию, что имеет смысл, так как они являются самой мощной версией. Или, возможно, у вас alias grep='grep -P'
где-то было.
решение3
Первая строка работает, если убрать ^
. Может, она работала, но не так, как вы предполагали? Сомневаюсь, что grep
поведение изменилось в таком важном месте.
echo
не транслирует escape-последовательности по умолчанию. -e
Для этого вам нужен. Аналогично с оболочкой. Вам нужно $'...'
заставить оболочку использовать escape-последовательности.