mcm*_*civ 23 shell environment-variables
我知道env
是一个shell命令,它可以用来打印当前环境变量的列表。而且据我了解,RANDOM
也是一个环境变量。
那么为什么当我env
在 Linux 上启动时,输出不包括RANDOM
?
Kus*_*nda 42
RANDOM
不是环境变量。它是由一些 shell 维护的 shell 变量。默认情况下一般不导出。这就是为什么它没有出现在env
.
一旦它至少被使用过一次,它就会出现在 的输出中set
,它本身就列出了当前 shell 会话中的 shell 变量(和函数)及其值。此行为取决于 shell 并pdksh
在 OpenBSD上使用RANDOM
,set
即使以前未使用,也会列出。
这个答案的其余部分涉及如果RANDOM
导出(即变成环境变量)可能会发生什么。
导出它export RANDOM
会使它成为环境变量,但它的使用将受到严重限制,因为它在子进程中的值将是“随机但静态的”(意味着它将是一个不变的随机数)。壳之间的确切行为不同。
我在pdksh
下面的示例中在 OpenBSD 上使用,并且在每次awk
运行中获得一个新的随机值(但在同一实例中每次都具有相同的值awk
)。使用bash
,我将在所有 的调用中获得完全相同的随机值awk
。
$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
25444 25444
$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
30906 30906
Run Code Online (Sandbox Code Playgroud)
在 中bash
,RANDOM
无论RANDOM
在 shell 中如何使用, 的导出值都将保持静态(每次使用 时$RANDOM
仍会给出一个新值)。
这是因为每个参考shell变量 RANDOM
在bash
使shell访问其内部get_random()
功能来给变量赋新的随机值,但外壳不更新环境变量 RANDOM
。这是因为与其他动态行为类似的bash
变量,例如LINENO
,SECONDS
,BASHPID
等。
要更新环境变量RANDOM
中bash
,你将不得不为它分配shell变量的值,RANDOM
并重新将其导出:
export RANDOM="$RANDOM"
Run Code Online (Sandbox Code Playgroud)
我不清楚这是否会产生重新播种随机数生成器的额外副作用bash
(但有根据的猜测是不会)。
ter*_*don 16
并非在 shell 会话中设置的所有变量都是环境变量。“环境变量”仅指使用export
内置函数导出到环境中的那些变量。该env
命令仅打印此类环境变量。例如:
$ foo="bar"
$ env | grep foo ## returns nothing
$ export foo
$ env | grep foo ## now, env will print it
foo=bar
Run Code Online (Sandbox Code Playgroud)
如果要查看会话中设置的所有变量,无论它们是否已导出,都可以使用set
:
$ set | grep foo=
foo=bar
Run Code Online (Sandbox Code Playgroud)
该set
内建也返回功能,所以只看到变量,您可以使用:
set | grep '^[^[:space:]]*='
Run Code Online (Sandbox Code Playgroud)
最后,该RANDOM
变量的特殊之处在于它仅在您引用它时才被赋予一个值。这在bash(1) 中提到:
RANDOM
每次引用此参数时,都会生成 0 到 32767 之间的随机整数。随机数序列可以通过为 分配一个值来初始化
RANDOM
。如果RANDOM
未设置,它将失去其特殊属性,即使随后被重置。
因此,即使它是您认为的环境变量,它也不会显示出来,env
因为直到您第一次调用它时才会设置它。这也是为什么它没有显示在set
:
$ set | grep RAN ## returns nothing, RANDOM is unset
$ echo "$RANDOM" ## this will assign a value to RANDOM
1234
$ set | grep RAN ## so now it will also appear in the output of set
RANDOM=1234
Run Code Online (Sandbox Code Playgroud)
大多数 shell 都会设置或使用许多其他变量,这些变量默认情况下不会导出到子进程。
在 Bash 中,有一些明显是 Bash 特有的:
$ echo "${!BASH*}"
BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND BASH_LINENO BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION
$ echo $BASH_VERSION
4.4.12(1)-release
$ env|grep -c BASH
0
Run Code Online (Sandbox Code Playgroud)
然后还有更标准的变量,例如OPTIND
and OPTERR
(由getopts
)、and PS2
, PS3
(辅助提示符),甚至还有另一个“神奇”变量:(SECONDS
显示自 shell 启动以来的时间(以秒为单位))
在 Bash 中,您可以通过 . 查看所有变量及其导出状态declare -p
。带 标记的-x
是导出的,不带标记的x
是不导出的。(有些会有其他标志,例如i
整数或r
只读。)
在 Zsh 或 ksh93 中,您可以使用,但 Zsh 通过在输出中更改为 来typeset -p
标记导出的变量,而不是使用标志。本身也会显示所有导出的变量,但这与运行 得到的结果大致相同。typeset
export
export
env