是否可以在 POSIX shell 脚本中恢复原始环境?

是否可以在 POSIX shell 脚本中恢复原始环境?

是否可以恢复调用 shell 脚本的原始环境?我并不是想编写一个依赖于访问原始环境的能力的程序,我想知道它是否是保证无法访问

我有一个简单的 shell 脚本,它创建一个新的环境变量并更改 PATH 的值。

#!/bin/sh

PATH=/usr/bin
NEW_VAR=new_var_value; export NEW_VAR

env

有没有办法恢复 的原始值,PATH或者有办法告诉它NEW_VAR在执行 shell 脚本时最初不存在?

我知道argvenvp可执行文件的路径都是在execv*(2)系统调用的早期设置的,但我不确定它们存储在“哪里”或“如何”。我的猜测是,使用、和 操作参数向量shift和环境的能力实际上并没有改变 和 的基本设置。 shell 内部只有逻辑来确保新调用在调用另一个命令时使用正确的命令(例如)。exportunexportargvenvpexecv*(2)envpsome-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 本身没有提供任何开箱即用的方法来执行此操作。我可以想到几种方法来接近这个目标:

  1. 查看父级中存在的环境(例如,/proc/pid/environLinux 中的环境),并根据该环境从头开始重新填充环境。这可能会也可能不会起作用,因为
    • 父母不一定拥有与孩子开始时相同的环境
    • 父级可能不再存在
    • 孩子可能无权访问父母的环境(例如,在放弃特权的情况下)
  2. 在脚本开头保存环境(例如,在开头使用export -p或)并在稍后恢复。/proc/self/environ这工作得很好,但你必须自己编写逻辑来恢复它。
  3. 当你设置一个新的环境变量时,通过一个函数来完成它,该函数首先存储旧的变量值,然后你可以通过相同的函数恢复它(或者手动完成,通过将其存储在例如,$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

相关内容