![导出其中包含点 (.) 的变量](https://linux22.com/image/50861/%E5%AF%BC%E5%87%BA%E5%85%B6%E4%B8%AD%E5%8C%85%E5%90%AB%E7%82%B9%20(.)%20%E7%9A%84%E5%8F%98%E9%87%8F.png)
如何导出其中包含点的变量。当我尝试时,我得到“无效的变量名称”:
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
无论如何都要定义它。但话又说回来,您将无法使用正常的 shell 语法访问它。在这种情况下,您可能需要另一种语言,例如 perl:
perl -e 'print $ENV{"my.home"}'
例如
env "my.home=/tmp/someDir" perl -le 'print $ENV{"my.home"}'
应该打印你的路径。
答案2
虽然环境变量可以具有不包含等号或空字节的任何名称(包括空字符串),但 shell 将环境变量映射到 shell 变量,并且在大多数 shell 中,变量名称仅限于 ASCII 字母数字字符,并且_
第一个字符可以是“ t 是一个数字(除了位置参数和其他特殊参数,如$*
、$-
、$@
、 …(未映射到相应的环境变量))。另请注意,一些变量是保留/特殊通过/到外壳。
例外情况:
shell
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
和(也yash
但仅适用于单字节字符)支持当前语言环境中的数字,而不仅仅是 ASCII 字符。zsh
bash
$ Stéphane=1 $ echo "$Stéphane" 1
在这些 shell 中,您可以更改区域设置以将大多数字符视为 alpha,但这对于 ASCII 字符(例如
.
.您可以愚弄zsh
或ksh
认为£
它是一个字母,但不是那个字母.
或任何其他 ASCII 字符(在变量名称中允许使用字符的情况下,[[:alpha:]]
例如对于 glob 而言)。ksh93
具有名称包含点(如 )的特殊变量${.sh.version}
,但这些变量未映射到环境变量并且是特殊的。这.
是为了确保它不与其他变量冲突。如果它选择调用它$sh_version
,那么它可能会破坏已经使用该变量的脚本(例如,请参阅zsh
其$path
或$commands
特殊数组/哈希变量(a la csh)如何出现问题,从而破坏某些脚本)。
请注意,除了不支持这些变量的 shell 之外,某些 shell(如 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 %%%
%%%
总而言之,最好是坚持使用大多数 shell 支持的变量名,甚至尝试对环境变量使用大写(对未导出的 shell 变量使用小写或混合大小写),避免使用 shell 中特殊的变量名(例如IFS
、PS1
、BASH_VERSION
...)。
如果您确实需要在不支持它们但不丢弃它们的 shell 中设置这样的变量,您可以自己重新执行,例如:
#! /bin/ksh -
perl -e 'exit 1 unless defined($ENV{"a.b"})' || exec env a.b=%%% "$0" "$@"
(显然,如果您需要在脚本中间执行此操作,那将无济于事,但您可以看看那种方法通过重新执行保存和恢复 shell 执行环境)。或者尝试调试器方法:
gdb --batch-silent -ex 'call putenv("a.b=%%%")' --pid="$$"
(这个似乎可以在 Linux amd64 上使用zsh
、yash
、csh
和tcsh
,但不能与我尝试过的任何其他 shell 一起使用(mksh
、ksh93
、bash
、dash
))。
答案3
正如其他帖子指出的那样,最常见的 shell 不允许设置名称中带有句点的环境变量。然而,我发现一些情况,特别是涉及 Docker 和调用的程序时,软件需要带有句点的键值。
但是,在每种情况下,这些键值对都可以通过环境变量以外的其他方式传递给程序。例如,在 Ant 中,您可以使用“-propertyfile(文件名)”来传入属性文件格式的键值集合。 Confd 允许“-backend file -file(yaml 文件)”。
我以“C__any_value='my.property.key=the value'”的形式传递了环境变量。然后我切换程序调用以首先生成文件:
set | awk -- 'BEGIN { FS="'\''" } /^C__/ {print $2}' > my-key-values.txt
在 Borne Shell 中,该set
命令将以以下形式在单独的行上输出每个属性
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
(精确的输出取决于您的 shell。)您将需要采取额外的步骤来解码转义的引号。
答案4
@michas 的答案非常正确,但可以将其扩展为export
使用点环境名称来模拟函数。
要“导出”此类变量,您可以使用命令exec
在当前 shell 中env
。例如,要导出test.env=foo
变量,请使用:
exec env "test.env=foo" $SHELL
Exec 将用新进程替换当前 shell,其中新进程将是当前 shell 的新实例 ( $SHELL
) 并带有附加环境变量test.env
(由 添加env "test.env=foo"
)。因此,执行此命令后,您可以从进程访问它,例如:
perl -e 'print $ENV{"test.env"}'