Почему
grep e\\.g\\. <<< "this is an e.g. wow"
и
grep e\.g\. <<< "this is an e.g. wow"
сделать то же самое?
Если я добавлю третью косую черту, это также даст тот же результат. НО, как только я добавляю четвертый слеш, он больше не работает. Это связано с вопросом из старого экзамена для класса. Он спросил, будет ли работать тот, у кого есть две обратные косые черты, чтобы вывести строку с «например», я изначально думал, что это не сработает, но я попытался убедиться, и это сработало. Какое объяснение?
bash
shell
regular-expression
quoting
Уайатт Грант
источник
источник
\\\.
и даст grep,\.
но это не так. Хороший вопросОтветы:
Во-первых, обратите внимание, что одиночная косая черта слишком сильно совпадает:
Что касается Bash , то экранированный период совпадает с периодом. Bash проходит на период, чтобы grep . Для grep точка соответствует чему угодно.
Теперь рассмотрим:
Когда Bash видит двойную косую черту, он уменьшает ее до одной косой черты и передает ее на grep, который в первом из трех тестов, приведенных выше, видит, как мы хотим, одну косую черту перед точкой. Таким образом, это правильно делает.
С тройной косой чертой Bash уменьшает первые две до одной косой черты. Затем он видит
\.
. Поскольку экранированный период не имеет особого значения для Bash, он сводится к обычному периоду. В результате grep видит, как мы хотим, косую черту перед точкой.С четырьмя слешами Bash уменьшает каждую пару до одного слеша. Bash передает grep две косые черты и точку. grep видит две косые черты и точку и уменьшает две косые черты до одного буквального слеша. Если за вводом нет буквального слеша, за которым следует какой-либо символ, совпадений нет.
Чтобы проиллюстрировать это последнее, помните, что внутри одинарных кавычек все символы являются буквальными. Таким образом, учитывая следующие три входные строки, команда grep совпадает только в строке с буквенной косой чертой во входных данных:
Краткое изложение поведения Баша
Для Bash правила
Две косые черты уменьшаются до одной косой черты.
Косая черта перед нормальным символом, например точка, является просто нормальным символом (точка).
Таким образом:
Существует простой способ избежать этой путаницы: в командной строке Bash регулярные выражения следует помещать в одинарные кавычки. Внутри одинарных кавычек, Bash оставляет все в покое.
источник
echo
утверждение, иллюстрирующее, что делает bash в этих случаях.\.
или.
. Для bash оба они одинаковы: они эквивалентны обычному периоду. Следовательно, в целом то, что bash предоставляет grep, одинаково для обоих: одиночная косая черта, за которой следует точка.echo
не очень надежного способа тестирования регулярных выражений из-за множества реализаций этой программы. Например под моим zsh (встроенный echo)echo \. \\. \\\. \\\\. \\\\\.
выдает. \. \. \. \.
, но/bin/echo \. \\. \\\. \\\\. \\\\\.
возвращает. \. \. \\. \\.
. Что-то вродеprintf "%s" ...
, вероятно, лучший способ.Вывод одинаков только для вашей строки, но в целом эти регулярные выражения делают разные вещи. Давайте немного изменим ваш пример, добавив второй шаблон
e,g,
(с запятыми), третийe\.g\.
(точки), четвертыйe\,g\,
(запятые) и-o
опцию grep для печати только соответствующих частей.В следующем случае
.
соответствовать любому символу (уведомление''
вокругe.g.
, я пришел к этому позже)Далее мы убегаем
.
с обратной косой чертой\
, так.
что будет сопоставлено только литерал :Но мы можем убежать
\
с другим\
, так что за литералом\
будет следовать.
(то есть любой символ):Но если мы хотим сопоставить только
\.
не,\,
тогда\
нужен еще один, чтобы избежать особого значения точки:Теперь, поскольку вы не использовали
''
аргумент grep, вам нужно добавить еще одну обратную косую черту, чтобы избежать обратной косой черты из интерпретации оболочки, поэтому:источник
Когда вы делаете a
grep e\.g\.
, оболочка потребляет обратную косую черту, таким образом вы делаете agrep e.g.
, что соответствует. Когда вы делаете agrep e\\.g\\.
, оболочка снова потребляет косую черту, и теперь вы делаете agrep e\.\g.
, что снова совпадает. Теперь обратный слеш к оболочке выглядит следующим образом\\
. Итак, когда у вас есть\\
, первая - escape-последовательность, вторая - буквальная обратная косая черта. Когда вы делаете agrep e\\\.g\\\.
, оно все равно заканчивается темgrep e\.\g.
, что не существует escape-последовательности (\
) перед первой,\
чтобы сделать ее литералом\
. Имейте в виду, \ это обратная косая черта, и вgrep e\\\\.\\\\g
итоге получаетсяgrep e\\.g\\.
, что, очевидно, не совпадает.Чтобы увидеть, как оболочка видит, что вы делаете, используйте echo (например,
echo grep e\\.g\\. <<< "this is an e.g. wow"
vs.echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"
)источник
Две команды выдают одинаковый вывод только для вашего ввода, но в остальном они различны. Чтобы понять, что происходит, мы должны знать, как параметр интерпретируется сначала,
bash
а затем -grep
.Спасаясь в Баш
\
является специальным символом, который отменяет особое значение следующего символа, включая\
самого себя. Если следующий символ не имеет специального значения, он передается без изменений. Примеры с командой и результатом:echo \a
:a
- обычный персонаж сбежал дает символecho \\
:\
- экранированный специальный символ дает символecho \\\a
:\a
- комбинация особая, обычнаяecho \\\\
:\\
- комбинация особая, особеннаяecho
напечатает полученную строку после того, какbash
интерпретирует ее. Более подробная информация: Баш документация , Баш хакеров вики , спецификации POSIX ..
не имеет особого значения вbash
. Это обычный символ для оболочки. Ниже приведены последовательности, относящиеся к вашим примерам:echo .
:.
echo \.
:.
echo \\.
:\.
echo \\\.
:\.
echo \\\\.
:\\.
Более простое решение для литеральных строк в bash
Чтобы передать параметры буквально,
bash
вы можете использовать одинарную кавычку'
. Между одинарными кавычками вам не нужно заботиться об особом значении символов, потому что одинарные кавычки - это единственный символ с особым значением. Вы можете вставить одинарную кавычку после заключения первой части строки. Примерecho 'part1'\''part2'
:part1'part2
Регулярное выражение в grep
\
это экранирующий символ с таким же значением, как вbash
..
это специальный символ, который представляет собой единственное вхождение любого символа . Смотрите: POSIX regex , GNU grep regex . Примеры регулярных выражений:.
- соответствует любому символу, какa
или.
\.
- соответствует только.
буквальноВаши примеры
На второй строке каждого примера ниже вы найдете эквивалент в одинарные кавычки ,
'
показывая , какие символьная строка передается поbash
сgrep
. Затем после выполненияgrep
экранирования единственным возможным специальным символом в примерах является.
сопоставление с любым символом. В третьей строке есть описание, которому соответствует выражение.grep e.g. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
любой символg
любой символ - соответствуетe.g.
и, возможно, другие строки, такие какeagb
grep e\.g\. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
любой символg
любой символ - соответствуетe.g.
и, возможно, другие строки, такие какexgy
grep e\\.g\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
буквально - только совпаденияe.g.
grep e\\\.g\\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
буквально - только совпаденияe.g.
grep e\\\\.g\\\\. <<< "this is an e.g. wow"
grep 'e\\.g\\.' <<< "this is an e.g. wow"
e\
любой символg\
любой символ - не совпадаетe.g.
источник