Подтвердить что ты не робот

Почему\$сокращается до $in backquotes [хотя и не внутри $(...)]?

Перейдя через стандарт POSIX, я столкнулся с другим довольно техническим/бессмысленным вопросом. Это состояния:

В стиле обратной подстановки команды <backslash> сохраняется его буквальное значение, за исключением случаев, когда следуют: '$', '`' или <backslash>.

Легко понять, почему "`" и "\" теряют свои буквальные значения: вложенная подстановка команд требует "другого" backquote внутри подстановки команд, что, в свою очередь, вынуждает "потерять свое буквальное значение", Так, например, следующее поведение выглядит разумным:

$ echo $(echo \\\\)
\\
$ echo `echo \\\\`
\

Но как насчет '$'? I.e., что точка или, более конкретно, возможное преимущество следующей разницы?

$ echo $(echo \$\$)
$$
$ echo `echo \$\$`
4735

Как "$" сам по себе не исключается внутри backquotes, похоже, что вы будете использовать либо "$", либо "\\\ $" все время, но не средний случай "\ $".

Чтобы повторить,

$ echo `echo $$` # PID, OK
4735
$ echo `echo \\\$\\\$` # literal "$$", OK
$$
$ echo `echo \$\$` # What the point?
4735

PS: Я знаю, что этот вопрос довольно технический... Я сам все время хожу на более современную подстановку $(...), но мне все же интересно.

4b9b3361

Ответ 1

Добавив \, вы создадите внутреннюю подсечку, а не внешнюю оболочку. Хорошим примером могло бы стать начало запуска новой оболочки, например:

$ echo $$
4988
$ echo `sh -c 'echo $$'`
4988
$ echo `sh -c 'echo \$\$'`
4990
$ echo `sh -c 'echo \\\$\\\$'`
$$

Ответ 2

Основной ответ

Рассмотрим следующую команду, которая находит базовый каталог, где был установлен gcc:

gcc_base=$(dirname $(dirname $(which gcc)))

При обозначении $(...) нет проблем с синтаксическим разбором; это тривиально и является одной из основных причин, по которым рекомендуется использовать нотацию. Эквивалентная команда с использованием обратных тиков:

gcc_base=`dirname \`dirname \\\`which gcc\\\`\``

Когда оболочка сначала анализирует эту команду, она сталкивается с первым обратным ходом и должна найти соответствующий результат. Это, когда цитируемый раздел вступает в силу:

В стиле backquoted подстановки команды сохраняется его буквальное значение, за исключением случаев, когда следуют: '$', '`' или.

gcc_base=`dirname \`dirname \\\`which gcc\\\`\``
                  ^         ^ ^          ^ ^ ^
                  1         2 3          4 5 6
  • backslash-backtick - специальное правило
  • обратная косая черта - специальное правило
  • backslash-backtick - специальное правило
  • обратная косая черта - специальное правило
  • backslash-backtick - специальное правило
  • backslash-backtick - специальное правило

Таким образом, необработанный обратный ход в конце знаменует конец самой внешней команды обратного хода. Под-оболочка, обрабатывающая эту команду, видит:

dirname `dirname \`which gcc\``

Обратные обратные обратные экраны снова получают специальное обращение, а суб-под-оболочка видит:

dirname `which gcc`
  • Суб-суб-оболочка получает вид which gcc и оценивает его (например, /usr/gcc/v4.6.1/bin/gcc).
  • Sub-sub-shell оценивает dirname /usr/gcc/v4.6.1/bin/gcc и производит /usr/gcc/v4.6.1/bin.
  • Под-оболочка оценивает dirname /usr/gcc/v4.6.1/bin и производит /usr/gcc/v4.6.1.
  • Оболочка назначает /usr/gcc/v4.6.1 gcc_base.

В этом примере обратная косая черта сопровождалась только специальными символами - обратная косая черта, backtick, доллар. Более сложный пример имел бы, например, \" последовательности в команде, а затем специальное правило не применялось; \" просто будет скопирован без изменений и передан в соответствующую под-оболочку (ы).

Необычайно сложный материал

Например, предположим, что у вас была команда с пробелом в ее имени (не дай бог, и это показывает, почему!), например totally amazing (две пробелы, это более строгий тест, чем один пробел). Затем вы можете написать:

$ cmd="totally  amazing"
$ echo "$cmd"
totally  amazing
$ which "$cmd"
/Users/jleffler/bin/totally  amazing
$ dirname $(which "$cmd")
usage: dirname path
$ # Oops!
$ dirname "$(which \"\$cmd\")"
"$cmd": not found
.
$ # Oops!
$ dirname "$(which \"$cmd\")"
"totally: not found
amazing": not found
.
$ dirname "$(eval which \"$cmd\")"
totally amazing: not found
.
$ dirname "$(eval which \"\$cmd\")"
/Users/jleffler/bin
$ # Ouch, but at least that worked!
$ # But how to extend that to the next level?
$ dirname "$(eval dirname \"\$\(eval which \\\"\\\$cmd\\\"\)\")"
/Users/jleffler
$

Хорошо - хорошо, что "легкий"! Вам нужна лучшая причина, чтобы избежать пробелов в именах команд или имени пути? Я также убедился, что он корректно работает с путями, содержащими пробелы.

Итак, можем ли мы сжать цикл обучения для обратных циклов? Да...

$ cat x3.sh
cmd="totally  amazing"
which "$cmd"
dirname "`which \"$cmd\"`"
dirname "`dirname \"\`which \\"\$cmd\\\"\`\"`"
$ sh -x x3.sh
+ cmd='totally  amazing'
+ which 'totally  amazing'
/Users/jleffler/bin/totally  amazing
++ which 'totally  amazing'
+ dirname '/Users/jleffler/bin/totally  amazing'
/Users/jleffler/bin
+++ which 'totally  amazing'
++ dirname '/Users/jleffler/bin/totally  amazing'
+ dirname /Users/jleffler/bin
/Users/jleffler
$

Это все еще ужасный, сложный, неинтуитивный набор escape-последовательностей. Это на самом деле короче версии для обозначения $(...) и не использует никаких команд eval (которые всегда усложняют вещи).

Ответ 3

Это, вероятно, связано с тем странным образом, что оболочка Bourne анализирует подстановки (реальная оболочка Korn немного похожа, но большинство других оболочек вообще не обнаруживают странное поведение).

В принципе, анализатор оболочки Bourne не интерпретирует подстановки ($ и `) внутри двойных кавычек или замену параметров ($) в любом месте. Это делается только во время расширения. Кроме того, во многих случаях несогласованные кавычки (одиночные кавычки, двойные кавычки или обратные кавычки) не являются ошибкой; заключительная цитата предполагается в конце.

Одним из следствий является то, что если подстановка параметров с помощью слова, содержащего пробелы типа ${v+a b}, происходит вне двойных кавычек, он не обрабатывается правильно и вызывает ошибку расширения при его выполнении. Пробел должен быть процитирован. Другие оболочки не имеют этой проблемы.

Другим следствием является то, что двойные кавычки внутри backquotes внутри двойных кавычек не работают надежно. Например,

v=0; echo "`v=1; echo " $v "`echo b"

напечатает

 1 echo b

в большинстве оболочек (одна подстановка команды), но

 0 b

в оболочке Bourne и реальной оболочке Korn (ksh93) (две подстановки команд).

(Способы избежать вышеупомянутой проблемы - сначала назначить замену переменной, поэтому двойные кавычки не нужны или использовать подстановку в стиле нового стиля.)

Настоящая оболочка Korn (ksh93) пытается сохранить большую часть странного поведения оболочки Bourne, но выполняет синтаксические разбора во время разбора. Таким образом, ${v+a b} принимается, но приведенный выше пример имеет "странное" поведение. Еще одна странная вещь: что-то вроде

echo "`${v+pwd"

(результат аналогичен отсутствующей закрывающей скобке). И где открывающая скобка в сообщении об ошибке из

echo "`${v+pwd`"

пришли из?

В приведенном ниже сеансе показан неясный случай, когда $ и \$ отличаются неочевидным образом:

$ echo ${.sh.version}
Version JM 93u 2011-02-08
$ v=0; echo "`v=1; echo "${v+p q}"`echo b" 
p qecho b
$ v=0; echo "`v=1; echo "\${v+p q}"`echo b" 
p{ q}b

Ответ 4

В принципе, обратная косая черта - это escape-символ. Вы помещаете его перед тем, как другой персонаж представляет что-то особенное. Этими символами являются "n", "t", "$" и "\".

"\n" --> newline
"\t" --> tab (indent)
"\$" --> $ (because a $ before a word in shell denotes a variable)
"\\" --> \ 

Обратная косая черта перед символами интерпретируется только так, когда она находится внутри кавычек.

Если вы хотите найти дополнительную информацию или другие символы побега, перейдите здесь