
Я склонен заключать подстановки команд в кавычки, как показано ниже, даже когда присваиваю их вывод переменной:
var="$(command)"
А оно вообще нужно? Когда оно ломается? Принятый ответздесьпретензии:
DIRNAME="$(имя_каталога $FILE)"не будет делать то, что ты хочешьесли $FILE содержит пробелы или символы подстановки [?*.
Ссылка ведет на замечательную страницу Grey Cat Wiki о цитировании, но на этой странице не упоминается конкретно о цитировании подстановок команд. И при цитированиипеременнаяявно необходимо, цитирование самой подстановки команды, похоже, не требуется.
Однако тот же пост заканчивается так:
DIRNAME="$(dirname "$FILE")" — рекомендуемый способ. Вы можете заменить DIRNAME= командой и пробелом, не меняя ничего больше, и dirname получит правильную строку.
Я тоже всегда так думал и часто исправлял посты, в которых это не цитировалось. Однако, страница вики, ссылка на которую приведена выше, также утверждает, что:
Есть несколько случаев, когда двойные кавычки можно безопасно опустить:
С правой стороны простого присваивания. Вы можете написать foo=$bar без кавычек. Это соответствует POSIX.
[. . . ]
Хотя var=$(command)
это и не совсем «простое» задание, мне, тем не менее, не удалось найти случай, когда кавычки были бы действительно необходимы:
$ var=$(echo "foo bar baz") ## whitespace works
$ echo "$var"
foo bar baz
$ var=$(printf "foo\nbar * baz") ## so do globbing characters
$ echo "$var"
foo
bar * baz
$ var1="foo\nbar * baz"
$ var=$(printf "$var1") ## printing a variable doesn't make any difference
$ echo "$var"
foo
bar * baz
$ var=$(printf '%s\n' "$var1")
$ echo "$var"
foo\nbar * baz
$ var=$(printf -- '-e %s\n' "$var1") ## strings starting with - also work
$ echo "$var"
-e foo\nbar * baz
Конечно, кавычки абсолютно необходимы, если подстановка команд используется напрямую для таких вещей, как command1 "$(command2)"
, но, похоже, это не относится к случаю присвоения переменной.
Итак, что я упускаю? Нужны ли вообще кавычки? В каком случае кавычки будут подставлять командупри присвоении возвращаемого значения переменнойзащитить вас от? Или всегда можно не заключать в кавычки подстановку команды, если она находится в правой части операции присваивания переменной?
решение1
Вы делаетене нужновзять в кавычки выражение в правой части задания.
Что вас раздражает, так это то, что другой ответрекомендуеттем не менее цитирую. Но это касается только обслуживания кода.
Рассмотрим следующееправильныйпример:
DIRNAME=$(dirname "$FILE")
echo "debug: dirname is $DIRNAME"
ls "$DIRNAME"
Теперь, после некоторого времени использования этого скрипта, вы можете подумать, что отладочное сообщение можно удалить. Поэтому, используя редактор, вы удалите строку эха. Затем вы заметите, что вам больше не нужна переменная DIRNAME, и вы просто перемещаете команду ls
для замены левого участка назначения. Теперь вы можетезабудьте добавить необходимые цитатыи вы в конечном итоге получаете этосломанный сценарий:
ls $(dirname "$FILE")
Вероятность такой ошибки еще выше, если первый автор — эксперт по оболочке, а второй редактор — новичок.
Конечно, это спорный вопрос,рекомендация избегать функции переносимой оболочкидействительно полезно. Лично я делаю это в основном так, как он рекомендует. Я также делаю это для более "простых" заданий, таких как: var="${foo}"
(включая лишние фигурные скобки).
решение2
В качестве одной из ссылок можно привести:В руководстве Bash об этом сказано ясно:
Переменная может быть назначена с помощью оператора формы
name=[value]
Если значение не указано, переменной присваивается пустая строка. Все значения подвергаются тильде-расширению, расширению параметров и переменных, подстановке команд, арифметическому расширению и удалению кавычек (подробно ниже). [...]Разделение слов не выполняется., за исключением «$@», как объяснено ниже.Расширение имени файла не выполняется.
Никакого разделения слов, никакого расширения имени файла, поэтому нет необходимости в кавычках.
Что касается POSIX, раздел2.9.1 Простые команды:
2. Слова, которые не являются присвоениями переменных или перенаправлениями, должны быть расширены. Если после их раскрытия остаются какие-либо поля Если после раскрытия остаются какие-либо поля, первое поле должно считаться именем команды, а остальные поля — аргументами для команды.
[...]
4. Каждое присвоение переменной должно быть расширено для раскрытия тильды, раскрытия параметра, подстановки команды, арифметического раскрытия и удаления кавычек перед присвоением значения.
Я не уверен, следует ли это интерпретировать так, что разделение полей происходит только для расширений, выполненных на шаге 2? Шаг 4 делает этонетупоминается разделение поля, хотя раздел оРазделение полятакже не упоминает присвоение переменных как исключение из создания нескольких полей.