Ответ 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
, который также решил реализовать не-POSIXlocal
встроенный [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"
- если
- Если весь RHS равен
- В дополнение к
Пример
В этом примере показано, что в 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
.