Nat*_*ong 44 environment-variables
我刚遇到一个问题,显示我不清楚 shell 变量的范围。
我试图使用bundle install,这是一个 Ruby 命令,它使用 的值$GEM_HOME来完成其工作。我已经设置了$GEM_HOME,但是在我使用之前,该命令忽略了该值export,如export GEM_HOME=/some/path.
我读到这使变量以某种方式“全局”(也称为环境变量),但我不明白这意味着什么。我了解编程中的全局变量,但不了解不同的程序。
此外,鉴于我设置的此类变量仅适用于当前的 shell 会话,我将如何为守护进程设置它们?
shell 变量可以有哪些作用域?
enz*_*tib 36
这些进程被组织成一棵树:每个进程都有一个唯一的父进程,除此之外,init它PID总是为 1 并且没有父进程。
新进程的创建一般要经过一对fork/execv系统调用,其中子进程的环境是父进程的副本。
要将变量从 shell 放入环境中,您必须使用export该变量,以便它对所有子项递归可见。但请注意,如果子进程更改了变量的值,则更改后的值仅对其可见,并且在该更改之后创建的所有进程(如前面所述的副本)可见。
还要考虑到子进程可能会更改其环境,例如可以将其重置为默认值,例如可能会这样做login。
jll*_*gre 30
至少在kshand下bash,变量可以有三个作用域,而不是像目前所有剩余的答案所说的两个作用域。
除了导出(即环境)变量和 shell 未导出变量范围之外,还有第三个更窄的函数局部变量范围。
在带有typeset标记的shell 函数中声明的变量仅在它们声明的函数内部和从那里调用的(子)函数中可见。
这个ksh/bash代码:
# Create a shell script named /tmp/show that displays the scoped variables values.
echo 'echo [$environment] [$shell] [$local]' > /tmp/show
chmod +x /tmp/show
# Function local variable declaration
function f
{
typeset local=three
echo "in function":
. /tmp/show
}
# Global variable declaration
export environment=one
# Unexported (i.e. local) variable declaration
shell=two
# Call the function that creates a function local variable and
# display all three variable values from inside the function
f
# Display the three values from outside the function
echo "in shell":
. /tmp/show
# Display the same values from a subshell
echo "in subshell":
/tmp/show
# Display the same values from a disconnected shell (simulated here by a clean environment start)
echo "in other shell"
env -i /tmp/show
Run Code Online (Sandbox Code Playgroud)
产生这个输出:
in function:
[one] [two] [three]
in shell:
[one] [two] []
in subshell:
[one] [] []
in other shell
[] [] []
Run Code Online (Sandbox Code Playgroud)
如您所见,导出的变量从前三个位置显示,未导出的变量不会显示在当前 shell 之外,函数局部变量在函数本身之外没有任何值。最后一个测试根本没有显示任何值,这是因为导出的变量在 shell 之间不共享,即它们只能被继承,并且继承的值之后不会受到父 shell 的影响。
请注意,后一种行为与 Windows 完全不同,在 Windows 中您可以使用完全全局且由所有进程共享的系统变量。
Nat*_*ong 14
其他回答者帮助我理解 shell 变量范围是关于进程及其后代的。
当您ls在命令行上键入命令时,您实际上是在创建一个进程来运行ls程序。新进程将您的 shell 作为其父进程。
任何进程都可以有自己的“本地”变量,这些变量不会传递给子进程。它还可以设置“环境”变量,它们是。使用export会创建一个环境变量。无论哪种情况,不相关的进程(原始进程的对等进程)都不会看到变量;我们只控制子进程看到的内容。
假设您有一个 bash shell,我们将其称为 A。您键入bash,这将创建一个子进程 bash shell,我们将其称为 B。您export在 A 中调用的任何内容仍将在 B 中设置。
现在,在 B 中,你说FOO=b。将发生以下两种情况之一:
FOO,它将创建一个局部变量。B 的孩子不会得到它(除非 B 调用export)。FOO,它将为自己及其随后的分叉子项修改它。B 的孩子将看到 B 分配的值。但是,这根本不会影响A。这是一个快速演示。
FOO=a # set "local" environment variable
echo $FOO # 'a'
bash # forks a child process for the new shell
echo $FOO # not set
exit # return to original shell
echo $FOO # still 'a'
export FOO # make FOO an environment variable
bash # fork a new "child" shell
echo $FOO # outputs 'a'
FOO=b # modifies environment (not local) variable
bash # fork "grandchild" shell
echo $FOO # outputs 'b'
exit # back to child shell
exit # back to original shell
echo $FOO # outputs 'a'
Run Code Online (Sandbox Code Playgroud)
所有这些都解释了我最初的问题:我GEM_HOME在我的 shell 中设置,但是当我调用时bundle install,它创建了一个子进程。因为我没用过export,子进程没有收到shell的GEM_HOME.
您可以通过使用export -n FOO.
export FOO=a # Set environment variable
bash # fork a shell
echo $FOO # outputs 'a'
export -n FOO # remove environment var for children
bash # fork a shell
echo $FOO # Not set
exit # back up a level
echo $FOO # outputs 'a' - still a local variable
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
62328 次 |
| 最近记录: |