Почему мы дважды цитируем оценку знака доллара в Bash?

Я знаю, что одинарные кавычки не будут оценивать, что внутри, и двойные кавычки будут. Я часто вижу, как люди цитируют цитату оценки доллара. Вот некоторые примеры:

  • for i in "${indices[@]}"; do
  • if [ "${a}" == 0 ]; then
  • ffmpeg -framerate 2 -pattern_type glob -i "*.png" -pix_fmt yuv420p output.mp4

Что делать, если мы не будем делать двойное цитирование выражения знака доллара? AFAIK, цикл for все еще работает.

2 Solutions collect form web for “Почему мы дважды цитируем оценку знака доллара в Bash?”

Ваши три примера не совсем одинаковы.

В последних двух:

 if [ "${a}" == 0 ]; then ffmpeg -framerate 2 -pattern_type glob -i "*.png" -pix_fmt yuv420p output.mp4 

Если $a не был указан, а его значение содержит символы $IFS (по умолчанию пробел, табуляция и новая строка) или подстановочные символы, это приведет к [ более трех аргументов (рядом с [ и ] ), в результате чего ошибка; аналогично, если значение $a было пустой строкой, это привело бы к тому, что [ получить слишком мало аргументов:

 $ (a=0; [ $a == 0 ] && echo OK) OK 

(но только если $IFS настоящее время не содержит 0 )

 $ (a='foo bar'; [ $a == 0 ] && echo OK) bash: [: too many arguments 

(со значением по умолчанию $IFS )

 $ (a=; [ $a == 0 ] && echo OK) bash: [: ==: unary operator expected 

(даже с пустым $IFS или с zsh (который в противном случае не реализует этот неявный оператор split + glob при некорректном расширении))

 $ (a='*'; [ $a == 0 ] && echo OK) bash: [: too many arguments 

(при запуске в каталоге, содержащем как минимум 2 не скрытых файла).

При цитировании нет ошибок:

 $ (a='foo bar'; [ "$a" == 0 ] && echo OK) $ (a=; [ "$a" == 0 ] && echo OK) 

Ваш первый пример отличается. Правила о расширении в двойных кавычках являются особыми при использовании массивов; если a обозначает массив, то:

  • $a – это первый элемент массива (строго говоря, это ${a[0]} даже если элемент в индексе 0 не определен);

  • ${a[*]} или ${a[@]} являются элементами массива, дополнительно разбиваются на $IFS (пробел, табуляция, новая строка по умолчанию);

  • "${a[@]}" – это элементы массива, а не разделенные на $IFS .

Итак, ваш цикл for i in "${indices[@]}"; do ... for i in "${indices[@]}"; do ... фактически не работает одинаково, в зависимости от содержимого массива. Например:

 $ (declare -aa=(abc); printf '%s\n' $a) a $ (declare -aa=(abc); printf '%s\n' ${a[*]}) a b c $ (declare -aa=(a 'b c'); printf '%s\n' ${a[*]}) a b c $ (declare -aa=(a 'b c'); printf '%s\n' ${a[@]}) a b c $ (declare -aa=(a 'b c'); printf '%s\n' "${a[*]}") abc $ (declare -aa=(a 'b c'); printf '%s\n' "${a[@]}") a bc 

Короче говоря, это делается, чтобы избежать расширений, созданных специальными символами, которые могут быть внутри переменной, например ! , Двойные кавычки также называются «слабым цитированием», поскольку некоторые из символов будут интерпретироваться (знак доллара, обратная косая черта и обратная косая черта). Одиночные кавычки являются «сильными цитатами», и ничто не будет интерпретироваться.

Цитирование документации по bash :

3.1.2.3 Двойные котировки

Закрывающие символы в двойных кавычках ( " ) сохраняют буквальное значение всех символов в кавычках, за исключением $ , backquote , \ , и, когда расширение истории включено ! .. Когда оболочка находится в режиме POSIX (см. Bash POSIX Mode), в двойных кавычках не имеет особого значения, даже если расширение истории включено …

Примеры слабых и сильных цитат:

  • echo "Your PATH is: $PATH" – напечатает Your PATH is:<variable_content>
  • echo 'Your PATH is: $PATH' – напечатает Your PATH is: $PATH

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

Связанные вещи:

  • Последствия для безопасности, забывающие процитировать переменную в оболочках bash / POSIX
  • Wiki – Цитаты и побеги
  • Цитирование и побег
  • Как выполнить эхо-команду и включить возврат строки?
  • Escaping * с регулярными выражениями и Grep
  • Параметр синтаксического анализа скрипта Bash с кавычками
  • Сценарии - Папки с пробелами
  • Проблема с экранированием параметризованных аргументов
  • Какие символы мне нужно избегать при использовании sed в сценарии sh?
  • Как назначить пространственно-содержащиеся значения для переменных в bash, используя eval
  • Как вставить кавычки в командах bash
  • Количество обратных косых черт, необходимых для экранирования обратного слэжа регулярного выражения в командной строке
  • Почему -text = "$ @" пропускает только первое слово?
  • Как назначить имена файлов пробелу другой переменной без потери разделителя
  • Linux и Unix - лучшая ОС в мире.