Следует ли использовать кавычки в именах путей среды?

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

export PATH="/users/me/path:$PATH"

vs

export PATH=/users/me/path:$PATH

Google стиль Shell руководство предлагает избегать кавычек для имен путей. Напротив, многие популярные репозитории dotfiles (например, Zach Holman's здесь) цитаты использовать. Есть ли ситуации, когда выгодно использовать кавычки в пути?

3 ответов


кончик шляпы к @gniourf_gniourf и @chepner за помощь.

tl; dr

чтобы быть в безопасности, двойная цитата: он будет работать во всех случаях, во всех POSIX-подобных оболочках.

если вы хотите добавить ~путь, выборочно оставить ~/ без кавычек обеспечить ~ расширяется; например: export PATH=~/"bin:$PATH". см. ниже за правила ~ расширение в назначениях переменных.
В качестве альтернативы просто используйте $HOME внутри одной строки с двойными кавычками:
export PATH="$HOME/bin:$PATH"


примечание: к bash, ksh и zsh, но не для (в основном) строго совместимых с POSIX оболочек, таких как dash; таким образом, когда вы нацелены /bin/sh, вы должны дважды процитировать RHS export.[1]

  • двойной кавычки дополнительно, только если литерал часть вашего RHS (значение для назначения) не содержит ни пробелов, ни других метасимволов оболочки.
  • ли значения переменные, на которые ссылается содержит пробелы / метасимволы или нет не вопрос - см. ниже.
    • Еще Раз: Это тут с sh, когда export используется, поэтому всегда двойная цитата там.

причина, по которой вы можете уйти без двойного цитирования в данном случае заключается в том, что переменная-задание утверждения в POSIX-подобных оболочках интерпретируют их RHS по-разному чем аргументы перешло к команды, как описано в 2.9.1 из POSIX spec:

  • в частности, хотя нач слово-расщепление is выполнено, применяется только к нерасширенные (raw) RHS (вот почему вы do нужно цитировать с пробелами / метасимволами в литералы), а не к его результаты.

  • этой относится только к подлинной заявления о присвоении форма
    <name>=<value> на все POSIX-подобные оболочки
    , то есть, если есть нет имени команды перед именем переменной; обратите внимание, что это включает задания начинаются команде для определения специальных переменных среды для нее, например,foo=$bar cmd ....

  • задания в контексте других команд всегда следует дважды цитировать, чтобы быть сейф:

    • с sh (в (в основном) строго POSIX-совместимой оболочке, такой как dash) назначение с export трактуется как обычная команда и foo=$bar часть рассматривается как 1-й аргумент до export builtin и поэтому обрабатывается как обычно (при условии разделения слов результат тоже).
      (POSIX не указывает никаких других команд, включающих (явное) назначение переменных; declare, typeset и local нестандартные расширения).

    • bash, ksh, zsh, в понятном отклонении от POSIX, расширьте логику назначения до export foo=$bar и typeset/declare/local foo=$bar как хорошо. Другими словами: на bash, ksh, zsh, export/typeset/declare/local команды рассматриваются как задания, так что цитирование не является строго необходимым.

      • возможно, удивительно, dash, который также решил реализовать non-POSIX local builtin[2] , не распространяет на него логику присвоения; он согласуется с его export поведение, однако.
    • задания переданы env (например, env foo=$bar cmd ...) также подлежат расширению в качестве аргумента команды и поэтому нуждаются в двойном цитировании-за исключением zsh.

      • это env действует иначе export в ksh и bash в этом отношении связано с тем, что env это внешние утилиты, а export это shell builtin.
        (zsh'поведение s принципиально отличается от других снарядов, когда дело доходит до некотируемых ссылки на переменные).
  • Тильда (~) расширение происходит следующим образом подлинной назначение заявления:

    • кроме ~ нужно без кавычек, как обычно, применяется лишь:
      • если весь RHS это ~; например,:
        • foo=~ # same as: foo="$HOME"
      • иначе: только если и выполнены следующие условия:
        • если ~ запускает строку или ей предшествует без кавычек :
        • если ~ и без кавычек /.
        • например,
          foo=~/bin # same as foo="$HOME/bin"
          foo=$foo:~/bin # same as foo="$foo:$HOME/bin"

пример

этот пример демонстрирует, что в bash, ksh и zsh вы можете уйти без двойное цитирование, даже при использовании export, а I не рекомендую его.

#!/usr/bin/env bash
# or ksh or zsh - but NOT /bin/sh!

# Create env. variable with whitespace and other shell metacharacters
export FOO="b:c &|<> d"

# Extend the value - the double quotes here are optional, but ONLY 
# because the literal part, 'a:`, contains no whitespace or other shell metacharacters.
# To be safe, DO double-quote the RHS.
export FOO=a:$foo # OK - $FOO now contains 'a:b:c &|<> d'

[1] как указывает @gniourf_gniourf: использование export to изменить значение PATH является необязательным, поскольку после того, как переменная помечена как экспортированная, вы можете использовать регулярное назначение (PATH=...), чтобы изменить его значение.
Тем не менее, вы все еще можете выбрать использовать export, чтобы сделать явным, что изменяемая переменная экспортируется.

[2] @gniourf_gniourf заявляет, что будущая версия стандарта POSIX может ввести local builtin.


test 123 является допустимым именем пути в UNIX. Попробуй!--6-->

PATH=test 123

Он вернется:

123: command not found

или даже

export PATH=test 123

что вернет

bash export: `123': not a valid identifier

это ответ на твой вопрос?

честно говоря, я бы не стал следовать такому четвертой партии руководство по стилю. Хотя я удивлен, что даже Google рекламирует такие неправильные советы.

Я бы следуйте:

(осторожно расширенный)


я использовал эти ответы выше при настройке имен путей к среде в докере .env файл, и получил укус. Я помещаю это здесь для всех, кто ищет, как определить переменные среды для docker.

Docker compose считывает переменные среды из an .файл env, который существует в той же папке, что и docker compose, запускается, как указано здесь https://docs.docker.com/compose/env-file.

однако вместо обертывания значения в кавычки docker compose требуется переменная среды, определенная без кавычек, если кавычки не являются частью значения. Опять же, как указано в URL выше

нет специальной обработки кавычек (т. е. они будут часть VAL, вы были предупреждены;)

Я пытался установить NODE_PATH=./src для абсолютных путей для работы в приложении react, развертываемом docker, но написанном как NODE_PATH="./src". Это предупреждение вытащило меня из 4-часовой кроличьей норы.