![Bash:为什么“set”的行为不像我预期的那样?](https://linux22.com/image/16638/Bash%EF%BC%9A%E4%B8%BA%E4%BB%80%E4%B9%88%E2%80%9Cset%E2%80%9D%E7%9A%84%E8%A1%8C%E4%B8%BA%E4%B8%8D%E5%83%8F%E6%88%91%E9%A2%84%E6%9C%9F%E7%9A%84%E9%82%A3%E6%A0%B7%EF%BC%9F.png)
我观察到只有导出变量的值通过我的 Mac OS X 附加到我的 PATH 变量.bash_profile
。然而,本地设置变量的值则不能。为什么局部变量不能附加到路径中?
“你误解了一些事情,但是什么?把你困惑的代码贴出来。 ——昨天吉尔斯”
请考虑这个片段,我将 MONGODB 变量设置为:
set MONGODB="/usr/local/mongodb/bin"
export PATH=${PATH}:${MONGODB}
我source .bash_profile
在航站楼。我看到以下回声:
PATH=~/bin:/usr/bin:/usr/local/bin:/usr/local/sbin:
然而,如果我改为导出 MONGODB 并获取我的.bash_profile
,我会看到以下回显:
PATH=~/bin:/usr/bin:/usr/local/bin:/usr/local/sbin:/usr/local/mongodb/bin
也许,使用set
不当?
答案1
set MONGODB="/usr/local/mongodb/bin"
这不是变量赋值。 (它是 C shell(csh、tcsh)中的一个,但不是 Bourne 风格 shell(sh、ash、bash、ksh、zsh 等)中的一个。)这是对内置函数的调用set
,它设置位置参数,即$1
,$2
等。尝试在终端中运行此命令,然后echo $1
。
要将值赋给 shell 变量,只需编写
MONGODB="/usr/local/mongodb/bin"
这将创建一个 shell 变量(也称为(命名)参数),您可以使用$MONGODB
.该变量仍然保留在 shell 内部,除非您使用 .export 将其导出export MONGODB
。如果导出,该变量对于该 shell 启动的所有进程也是可见的,通过环境。您可以将作业和导出压缩为一行:
export MONGODB="/usr/local/mongodb/bin"
对于您正在做的事情,似乎不需要MONGODB
脚本外部,并且PATH
已经导出(导出变量后,如果分配新值,它将反映在环境中)。所以你可以写:
MONGODB="/usr/local/mongodb/bin"
PATH=${PATH}:${MONGODB}
答案2
我将尝试解释 shell 变量是如何工作的。将局部变量附加到像 PATH 这样的环境变量中是绝对可能的。
每个正在运行的进程都有一个环境变量列表。它们是名称=值对。当创建一个新进程时叉()它继承了这些变量(以及其他变量,如打开的文件、用户 ID 等)。相反,shell 变量是一个内部 shell 概念。创建新进程时不会继承它们。您可以导出 shell 变量并将其设为环境变量。当您在 shell 脚本中编写时,FOO='bar'
它是一个 shell 变量。您可以尝试创建 2 个脚本:
# test1.sh
FOO='bar'
sh test2.sh
# test2.sh
echo "${FOO}"
当您执行第一个脚本时,它会设置一个内部 shell 变量,然后调用 fork()。父 shell 进程将等待()为了让子进程完成,然后继续执行(如果有更多命令)。在子进程中执行()被调用来加载新的 shell。这个新进程不知道FOO。如果修改第一个脚本:
# test1.sh
export FOO='bar'
sh test2.sh
FOO 变量成为环境的一部分并继承到分叉进程。值得注意的是,环境并不是全球性的。子进程不能影响其父进程的环境变量。
# test3.sh
sh test4.sh
echo "${PATH}"
# test4.sh
export PATH="${PATH}:/new/path"
test4.sh 中的修改在 test3.sh 中不可见。信息根本就不是这样的。当子进程结束时,其环境将被丢弃。让我们更改test3.sh:
# test3.sh
source test4.sh
echo "${PATH}"
Source 是一个内置的 shell 命令。它告诉 shell 打开一个文件,然后读取并执行其内容。只有一个 shell 进程。这样调用者就可以看到环境变量甚至shell变量的修改。
您可能知道 PATH 是一个特殊的环境变量,它告诉 shell 在哪里查找其他可执行文件。当新的登录 shell 启动时,它会自动获取 .bash_profile。在那里声明的变量将是可见的。但是,如果在 .bash_profile 中使用 sh 调用其他脚本,则您在这些脚本中设置的 PATH 将丢失。
答案3
也许,使用“set”是不合适的?
是的,这就是你的问题。set
没有做你可能期望的事情。来自文档:
这个内置函数非常复杂,值得单独专门一节。
set
允许您更改 shell 选项的值并设置位置参数,或显示 shell 变量的名称和值。
请注意,它所做的事情列表中明显缺少“实际设置 shell 变量”。埋藏在所有文档中,你会发现它所做的是设置 shell位置参数对于你给出的论点。你只是给出一个论点,全部MONGODB="/usr/local/mongodb/bin"
。因此$1
被设置为该值(并且$#
被设置为 1,因为只有一个参数)。
反助记 Unix 命令名称得一分,是吧?
所以无论如何,尝试一下:
MONGODB=/usr/local/mongodb/bin
export PATH=${PATH}:${MONGODB}
它会起作用的。