Почему `echo -e“ \\\ SOME_TEXT ”` показывает только одну обратную косую черту?

19

Может кто-нибудь объяснить, что происходит за кулисами в экранировании персонажей в оболочке Linux? Я попробовал следующее и много гуглил, но безуспешно понял, что (и как) происходит:

root@sv01:~# echo -e "\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\\ Hello!"
\\\ Hello!
root@sv01:~# echo -e "\n Hello!"

 Hello!
root@sv01:~# echo -e "\\n Hello!"

 Hello!
root@sv01:~# echo -e "\\\n Hello!"
\n Hello!

Я там полностью потерялся, так, например, почему три обратные косые черты дают только одну обратную косую черту? Я ожидаю: первые два будут сброшены на один, третий не найдет ничего, что можно избежать, поэтому он останется косой чертой (строка в первом эксперименте), но происходит то, что третий просто исчезает.
Почему я получаю одну обратную косую черту из четырех \\\\ Hello? Я ожидаю, что каждая пара даст одну обратную косую черту -> две обратных косых черты.

И почему мне нужно три обратных слеша в последнем случае, чтобы избежать \ n? что происходит на фоне побега, чтобы получить это? а чем он отличается от \\nдела?

Я ценю любое объяснение того, что происходит в предыдущих строках.

Мухаммед Нурельдин
источник
echo -eв любом случае поведение не определяется стандартами - см. pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html . Выходные данные полностью определяются реализацией, если во входных данных есть буквальная обратная косая черта, и единственный допустимый параметр - это -n(что означает, что реализация, соответствующая стандартам, будет иметь echo -eпечать -eна своем выходе).
Чарльз Даффи
... даже если вы на 100% уверены, что ваша оболочка является bash, даже тогда echo -e она небезопасна: echoбудет вести себя в соответствии со стандартом, если включены оба параметра posixи xpg_echoпараметры времени выполнения, или если они скомпилированы с эквивалентными параметрами времени сборки. Безопасной практикой является использование printfвместо этого - см. Разделы ИСПОЛЬЗОВАНИЕ ПРИЛОЖЕНИЯ и ОБОСНОВАНИЕ вышеупомянутой ссылки, описывающие, как заставить printfдействовать в качестве замены echo.
Чарльз Даффи

Ответы:

28

Это потому bashи в echo -eсовокупности. Изman 1 bash

Обратный слэш ( \) без кавычек является escape-символом. Он сохраняет буквальное значение следующего символа, за исключением <newline>. [...]

Ограждающие символы в двойные кавычки сохраняет буквальное значение всех символов в кавычках, за исключением $`, \[...] обратная косая черта сохраняет свой особый смысл только тогда , когда следует один из следующих символов: $`, ", \, или <newline>.

Дело в том, что обратный слэш с двойными кавычками не всегда особенный.

Существуют различные реализации echoв целом, это встроенный bash; главное здесь это поведение:

Если -eдействует, распознаются следующие последовательности:
\\
обратная косая черта
[…]
\n
новая строка

Теперь мы можем расшифровать:

  1. echo -e "\ Hello!"- ничего особенного bash, ничего особенного echo; \остается.
  2. echo -e "\\ Hello!"- первое \говорит, bashчтобы относиться ко второму \буквально; echoполучает \ Hello!и действует как выше.
  3. echo -e "\\\ Hello!"- первое \говорит, bashчтобы относиться ко второму \буквально; echoполучает \\ Hello!и (из-за -e) это признает \\как \.
  4. echo -e "\\\\ Hello!"- первое \говорит, bashчтобы относиться ко второму \буквально; третий говорит то же самое о четвертом; echoполучает \\ Hello!и (из-за -e) это признает \\как \.
  5. echo -e "\\\\\ Hello!"- первое \говорит, bashчтобы относиться ко второму \буквально; третий говорит то же самое о четвертом; последний не особенный; echoполучает \\\ Hello!и (из-за -e) распознает начальный \\как \, последний \остается неизменным.

И так далее. Как видите, до четырех последовательных обратных слешей дают один результат. Вот почему вам нужно (по крайней мере) девять из них, чтобы получить три. 9 = 4 + 4 + 1.

Теперь с \n:

  1. echo -e "\n Hello!"- в этом нет ничего особенного bash, echo получает ту же строку и (из-за -e) интерпретирует ее \nкак новую строку .
  2. echo -e "\\n Hello!"- bashинтерпретирует \\как \; echoполучает \n Hello!и результат такой же, как указано выше.
  3. echo -e "\\\n Hello!"- bashинтерпретирует начальное \\как \; echoполучает \\n Hello!и (из-за -e) это интерпретирует \\как литерал, \который должен быть напечатан.

Результаты будут отличаться 'вместо "(из-за разного bashповедения) или без -e(из-за разного echoповедения).

Камиль Мачоровски
источник
1
Большое спасибо! Итак, есть два шага выхода: шаг, сделанный bash, и второй этап, по которому -eсудит текст, уже оцененный bash, это правильно? если это правильно, это устраняет путаницу. Не могли бы вы упомянуть, как sedведет себя? у него есть своя сборка в технике побега? так я имею в виду это ведет себя как эхо с -e?
Мухаммед Нурельдин
2
@ MohammedNoureldin Да, есть два шага. Ваш оригинальный вопрос в порядке, давайте не будем усложнять его sed. Вы можете задать еще один вопрос ( sedтолько о ), просто сначала проведите собственное исследование.
Камиль Мачоровски
3
@MohammedNoureldin sedбудет следовать тем же основным принципам: bash будет интерпретировать командную строку в соответствии с ее правилами, анализируя (и, возможно, удаляя) кавычки и экранируя. Результат , который получает передается sed, который интерпретирует его в соответствии с его вылетающих правилами. Кстати, вы можете упростить это, используя строку в одинарных кавычках bash, поскольку в ней не выполняется интерпретация escape-кода (посредством bash) - bash удаляет одинарные кавычки и передает то, что внутри них, непосредственно команде.
Гордон Дэвиссон
У меня все еще есть небольшая проблема на echo -e "\\\n Hello!"всякий случай. Здесь bash сбежит , и он станет \\n, затем -eизбежит двух приведенных в результате обратных наклонных черт, \\nи тогда они станут \n. Теперь, кто интерпретирует, \nчтобы сделать это новой строкой? Обычно, в случае echo -e "\n Hello!", bash ничего не делает и -eинтерпретирует \nкак новую строку. но в первой упомянутой ситуации процесс интерпретации был сделан до того, \nкак получить интерпретацию. Не могли бы вы объяснить это, пожалуйста?
Мохаммед Нурельдин
1
Хорошо, моя вина, я читал об этом в течение 2 дней с их ночами, поэтому, видимо, я начал смешивать дела, я думаю, что я получил что-то еще, в sedчем меня смутило прошлой ночью (возможно, я сделал что-то не так вчера), но теперь я попробовал снова то же самое с echo -eи sed, и я получил то же самое, что и исключено, спасибо!
Мухаммед Нурельдин