Экспорт переменной с точкой (.) внутри

Экспорт переменной с точкой (.) внутри

Как экспортировать переменную, в которой есть точка. Я получаю «недопустимое имя переменной», когда пытаюсь:

 export my.home=/tmp/someDir
-ksh: my.home=/tmp/someDir: invalid variable name

Даже экранирование метасимвола точка (.) не помогло.

$ export my\.home=/tmp/someDir
export: my.home=/tmp/someDir: is not an identifier

решение1

По крайней мере, для bashстраницы руководства синтаксис экспорта определяется следующим образом:

export [-fn] [name[=word]] ...

Он также определяет «имя» как:

   name   A  word  consisting  only  of alphanumeric characters and under‐
          scores, and beginning with an alphabetic character or an  under‐
          score.  Also referred to as an identifier.

Следовательно, вы действительно не можете определить переменную, my.homeпоскольку она не является допустимым идентификатором.

Я совершенно уверен, что ваш ksh имеет очень похожее определение идентификатора и поэтому не допускает такого рода переменных. (Посмотрите на его страницу руководства.)

Я также уверен, что существует какой-то общий стандарт (POSIX?), определяющий, что разрешено в качестве идентификатора (и, следовательно, имени переменной).


Если вам действительно по какой-то причине нужна такая переменная, вы можете использовать что-то вроде

env "my.home=/tmp/someDir" bash

чтобы определить его в любом случае. Но опять же, вы не сможете получить к нему доступ с помощью обычного синтаксиса оболочки. В этом случае вам, вероятно, понадобится другой язык, например perl:

perl -e 'print $ENV{"my.home"}'

Например

env "my.home=/tmp/someDir" perl -le 'print $ENV{"my.home"}'

должен вывести ваш путь.

решение2

Хотя переменные окружения могут иметь любое имя (включая пустую строку), не содержащее знак равенства или нулевой байт, оболочки сопоставляют переменные окружения с переменными оболочки, и в большинстве оболочек имена переменных ограничены буквенно-цифровыми символами ASCII, и _первый символ не может быть цифрой (за исключением позиционных параметров и других специальных, таких как $*, $-, $@, …, (которые не сопоставляются с соответствующими переменными окружения)). Также обратите внимание, что некоторые переменныезарезервированный/специальныйпо/к оболочке.

Исключения из этого правила:

  • Оболочка rcи ее производные esподдерживают akangaлюбые имена, кроме пустых строк и имен, состоящих только из цифр или содержащих =символы (и всегда экспортируют все свои переменные в среду, а также остерегайтесь специальных переменных, таких как *, status, pid...):

    ; '%$£"' = test
    ; echo $'%$£"'
    test
    ; '' = x
    zero-length variable name
    ;
    

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

    $ rc -c '+ = zzz; __ = zzz; a = (zzz xxx); env' | sed -n /zzz/l
    __2b=zzz$
    __5f_=zzz$
    a=zzz\001xxx$
    $ env +=x rc -c "echo $'+'"
    x
    $ env __2b=x rc -c "echo $'+'"
    x
    
  • AT&T и (также ksh, но только для однобайтовых символов) поддерживают числа в текущей локали, а не только ASCII.yashzshbash

    $ Stéphane=1
    $ echo "$Stéphane"
    1
    

    В этих оболочках вы можете изменить локаль, чтобы считать большинство символов буквами, но это все равно не будет работать для символов ASCII, таких как .. Вы можете обмануть zshили , kshзаставив думать, £что это буква, но не это .или любой другой символ ASCII (там, где речь идет о разрешении символов в именах переменных, не для [[:alpha:]]glob, например).

  • ksh93имеет специальные переменные, имя которых содержит точку, например ${.sh.version}, но они не сопоставлены с переменными окружения и являются специальными. Это .делается для того, чтобы убедиться, что это не конфликтует с другими переменными. Если бы он выбрал вызов $sh_version, то это могло бы потенциально сломать скрипты, которые уже использовали эту переменную (см., например, как zshвозникают проблемы с его $pathили $commandsспециальными переменными массива/хэша (a la csh), которые ломают некоторые скрипты).

Обратите внимание, что помимо оболочек, не поддерживающих эти переменные, некоторые оболочки, такие как pdksh/mksh, поддерживаютудалятьиз среды, которую они получают ( bashудаляет ту, у которой пустое имя, ashи kshудаляет bashте строки среды, которые не содержат =символ):

$ env %%%=test 1=%%% a.b=%%% mksh -c env | grep %%%
$ env %%%=test 1=%%% a.b=%%% bash -c env | grep %%%
%%%=test
a.b=%%%
1=%%%

$ perl -le '$ENV{""}="%%%"; exec "bash", "-c", "env"' | grep %%%
$ perl -le '$ENV{""}="%%%"; exec "zsh", "-c", "env"' | grep %%%
=%%%

$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
    execve("/bin/ash",a,e);}'|tcc -run - | grep %%%
$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
    execve("/bin/zsh",a,e);}'|tcc -run - | grep %%%
%%%

Подводя итог, лучше всего придерживаться имен переменных, поддерживаемых большинством оболочек, и даже стараться использовать заглавные буквы для переменных среды (и строчные или смешанные регистры для неэкспортируемых переменных оболочки), избегая тех, которые являются специальными в оболочках (например IFS, PS1, , BASH_VERSION...).

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

#! /bin/ksh -
perl -e 'exit 1 unless defined($ENV{"a.b"})' || exec env a.b=%%% "$0" "$@"

(разумеется, если вам нужно сделать это в середине сценария, это не поможет, но вы можете тогда взглянуть наэтот подходдля сохранения и восстановления среды выполнения оболочки через re-exec). Или попробуйте подход с отладчиком:

gdb --batch-silent -ex 'call putenv("a.b=%%%")' --pid="$$"

(кажется, этот вариант работает с zsh, yash, cshи tcshна Linux amd64, но не с какой-либо другой оболочкой, которую я пробовал ( mksh, ksh93, bash, dash)).

решение3

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

Однако в каждой из этих ситуаций эти пары ключ-значение могут быть переданы программе другими способами, а не только через переменные среды. Например, в Ant можно использовать "-propertyfile (имя_файла)" для передачи коллекции ключей-значений в формате файла свойств. Confd допускает "-backend file -file (yaml file)".

Я передал переменные окружения в форме "C__any_value='my.property.key=the value'". Затем я переключил вызов программы, чтобы сначала сгенерировать файл:

set | awk -- 'BEGIN { FS="'\''" } /^C__/ {print $2}' > my-key-values.txt

Команда setв Borne Shell выведет каждое свойство на отдельной строке в форме

C__any_value='my.property.key=the value'

Команда awkобработает только переменные среды, начинающиеся с C__, а затем извлечет значения, содержащиеся в одинарных кавычках.

Этот метод требует, чтобы значение переменной среды было установлено в точной форме, требуемой программой обработки. Кроме того, если значение свойства или ключ будут содержать одинарные кавычки, вам нужно будет изменить символ разделителя полей awk на что-то, что, как вы знаете, не будет отображаться, и окружить значение этим символом. Например, чтобы использовать %в качестве разделителя:

$ C__1="%my.key=the'value%"
$ set | awk -- 'BEGIN { FS="%" } /^C__/ {print $2}'
my.key=the'"'"'value

(точный вывод будет зависеть от вашей оболочки.) Вам нужно будет предпринять дополнительные шаги для декодирования экранирования кавычек.

решение4

Ответ от @michas вполне правильный, но его можно расширить для имитации exportфункции с точечными именами окружения.

Чтобы «экспортировать» такую ​​переменную, вы можете использовать execтекущую оболочку с envкомандой. Например, чтобы экспортировать test.env=fooпеременную, используйте:

exec env "test.env=foo" $SHELL

Exec заменит текущую оболочку новым процессом, где новый процесс будет новым экземпляром текущей оболочки ( $SHELL) с дополнительной переменной окружения test.env(добавленной env "test.env=foo"). Таким образом, после этой команды вы можете получить к ней доступ из вашего процесса, например:

perl -e 'print $ENV{"test.env"}'

Связанный контент