是否可以恢复调用 shell 脚本的原始环境?我并不是想编写一个依赖于访问原始环境的能力的程序,我想知道它是否是保证无法访问。
我有一个简单的 shell 脚本,它创建一个新的环境变量并更改 PATH 的值。
#!/bin/sh
PATH=/usr/bin
NEW_VAR=new_var_value; export NEW_VAR
env
有没有办法恢复 的原始值,PATH
或者有办法告诉它NEW_VAR
在执行 shell 脚本时最初不存在?
我知道argv
,envp
可执行文件的路径都是在execv*(2)
系统调用的早期设置的,但我不确定它们存储在“哪里”或“如何”。我的猜测是,使用、和 操作参数向量shift
和环境的能力实际上并没有改变 和 的基本设置。 shell 内部只有逻辑来确保新调用在调用另一个命令时使用正确的命令(例如)。export
unexport
argv
envp
execv*(2)
envp
some-command | LC_ALL=C sort
答案1
当命令运行时,大多数系统允许您使用该ps
命令显示其环境。它无法移植,并且并非所有系统都允许可靠的解析,但如果您想要的只是以适用于特定 Unix 变体的方式提取初始环境的“有趣”部分,那很容易。例如,在 Linux 和 *BSD 上:
ps eww $$
或者,在 Solaris 和 Linux 上:
cat /proc/$$/environ
或者,在 Solaris 和 AIX 上:
pargs -e $$
如果需要隐藏环境以前的内容,请确保所有 shell 进程(包括后台子 shell)都已退出。要以不泄漏的方式传递数据,请使用管道而不是环境变量。
exec sh -c 'unset pw; pw=$PASSWORD; unset PASSWORD; printf %s "$pw" | exec theprogram'
请注意,在大多数(所有现代?) Unix 变体上,进程的环境仅对同一用户可见。通常只有参数对任何运行的用户可见ps
。所以环境中传递机密数据是可以的;摆脱它只是一个强化问题,而不是基本安全问题。
答案2
POSIX 本身没有提供任何开箱即用的方法来执行此操作。我可以想到几种方法来接近这个目标:
- 查看父级中存在的环境(例如,
/proc/pid/environ
Linux 中的环境),并根据该环境从头开始重新填充环境。这可能会也可能不会起作用,因为- 父母不一定拥有与孩子开始时相同的环境
- 父级可能不再存在
- 孩子可能无权访问父母的环境(例如,在放弃特权的情况下)
- 在脚本开头保存环境(例如,在开头使用
export -p
或)并在稍后恢复。/proc/self/environ
这工作得很好,但你必须自己编写逻辑来恢复它。 - 当你设置一个新的环境变量时,通过一个函数来完成它,该函数首先存储旧的变量值,然后你可以通过相同的函数恢复它(或者手动完成,通过将其存储在例如,
$OLD_PATH
)。这可行,但很麻烦,而且很容易忘记这样做。例如:
$OLD_PATH=$PATH
# do something
$PATH=$OLD_PATH
答案3
如果您想在进行任何修改之前了解环境的状态,那么为什么不在执行任何操作之前保存它呢?例如,
#!/bin/sh
PATH_orig=$PATH; # save the original PATH
case ${NEW_VAR++} in
? ) echo 'Achtung: NEW_VAR is already in the original environment' ;;
* ) echo 'NEW_VAR not found in the original environment' ;;
esac
OLD_ENV=$(export -p) # will save your original env in a source-able manner
### And now make your changes...
PATH=/usr/bin
NEW_VAR="foo"; export NEW_VAR