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

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

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

vs

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

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

Ответы

Ответ 1

Совет о шляпе @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:

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

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

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

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

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

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

      • Это env действует иначе, чем export в ksh и bash в этом отношении связано с тем, что env является внешней утилитой, тогда как export является встроенной оболочкой.
        (zsh поведение существенно отличается от поведения других оболочек, когда речь идет о некотируемых ссылках на переменные).
  • Расширение Tilde (~) происходит в действительных операторах присваивания:

    • В дополнение к ~, нуждающемуся в некотировании, как обычно, он применяется только:
      • Если весь 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, но я не рекомендую его.

#!/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 для изменения значения PATH является необязательным, поскольку, как только переменная помечена как экспортированная, вы можете использовать регулярное назначение (PATH=...), чтобы изменить его значение.
Тем не менее, вы все равно можете использовать export, чтобы сделать его явным, что изменяемая переменная экспортируется.

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

Ответ 2

test 123 - это допустимое имя пути в UNIX. Попробуйте

PATH=test 123

Он вернется:

123: command not found

Или даже

export PATH=test 123

который вернет

bash export: `123': not a valid identifier

Отвечает ли ваш вопрос на ваш вопрос?

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

Я бы сказал:

(для тщательного продления)

Ответ 3

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

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

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

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

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