【问题标题】:Sanitize environment with command or bash script?使用命令或 bash 脚本清理环境?
【发布时间】:2012-03-29 02:04:06
【问题描述】:

在 Bash shell 中,我想在使用命令运行时首先清理环境。

我想取消设置所有环境变量,只设置对 shell 运行至关重要的变量,以及我的脚本完成任务所需的变量。

有没有办法以一种简单而干净的方式做到这一点?

【问题讨论】:

  • 在 Bash 中,env 命令有一个标志-i,它将清除所有环境变量以默认登录。所以运行这个:env -i bash
  • 这并不是真正的“在 bash 中”——env 是标准的 UNIX 命令,而不是内置的 bash。你完全可以在没有 shell 的情况下调用它(来自 C、Python 等)。

标签: linux bash


【解决方案1】:

这是一种无需启动新 shell 即可执行此操作的方法,即使使用奇怪的变量名(包含空格/换行符)也可以使用:

while IFS='=' read -rd '' name value ; do unset "$name" ; done < /proc/self/environ

缺点是它是特定于 Linux 的,并且依赖于挂载的 procfs。

这将取消设置所有环境变量,甚至HOMEPATH。这可能是也可能不是您想要的。

解释:/proc/PID/environ 包含进程的环境块,作为一系列以零分隔的NAME=VALUE 字符串。我们使用read 循环,将字段分隔符IFS 设置为=,以便我们可以从每个字符串中拆分名称和值。通过将行分隔符 (-d) 设置为空字符串,我们使read 使用空字符(以空字符结尾的字符串的“第一个”字符)来分割行。然后,依次取消设置每个名称(注意引用它)。

【讨论】:

  • @CharlesDuffy 你的说法很容易被env $'a\nb=c\nd' bash -c env 反驳(bash 4.4.23(1)-release)。还是你的意思是别的?
  • ...好吧,设法追查到我从哪里得到那个错误的印象。 POSIX 允许丢弃这些变量,但不是所有的 shell 都这样做;是什么让我记错了与stackoverflow.com/questions/36989263/… 相关的研究——请参阅其中的参考:discarding-variables-with-invalid-names-is-permitted 断言。
【解决方案2】:

取消设置所有环境变量 bash linux

命令:env -i bash

示例,创建本地和环境变量,然后重置为默认值:

el@defiant ~$ LOCAL_DOGE="such variable"
el@defiant ~$ ENVIRONMENT_DOGE="much code"
el@defiant ~$ export ENVIRONMENT_DOGE
el@defiant ~$ set | grep DOGE
ENVIRONMENT_DOGE='much code'
LOCAL_DOGE='such variable'
el@defiant ~$ env | grep DOGE
ENVIRONMENT_DOGE=much code
el@defiant ~$ env -i bash
el@defiant ~$ set | grep DOGE
el@defiant ~$ env | grep DOGE
el@defiant ~$

哇,LOCAL_DOGEENVIRONMENT_DOGE 用一个命令就消失了。

取消设置所有环境变量 bash linux,备用方式。

env - /bin/bash

示例:

el@defiant ~$ DOGE1="one"
el@defiant ~$ export DOGE2="two"
el@defiant ~$ set | grep DOGE
DOGE1=one
DOGE2=two
el@defiant ~$ env | grep DOGE
DOGE2=two
el@defiant ~$ env - /bin/bash
el@defiant ~$ set | grep DOGE
el@defiant ~$ env | grep DOGE

【讨论】:

  • 这不是 OP 想要的,恕我直言;或者至少不是正确的答案。你在这里所做的只是一个新的SUBSHELL,没有继承旧的环境。如果你这样做几次,你会耗尽内存:p。
  • 同意 Carlo,这绝对不是解决方案……它不会取消设置变量,而是开始一个新会话。
【解决方案3】:

我在尝试创建辅助函数以避免代理时遇到了这个问题。我来叫它proxyless。其代码如下:

proxyless () {
  cmd=(unset http_proxy https_proxy \; ${@})
  bash -c "${cmd[*]}"
}

我正在有效地做的是构建一个命令数组以传递给 bash。因此,我使用unset 来做显而易见的事情,并将所有命令参数放在数组的末尾。所以,例如,

$ proxyless curl google.com

会变成(根据bash -x

$ bash -c 'unset http_proxy https_proxy; curl google.com'

【讨论】:

  • 不能正确处理空格。尝试:proxyless printf '%q\n' a b 'c d' $'e\nf' 并比较没有proxyless 的输出。另外,问题是如何删除 all 环境变量。
【解决方案4】:

扩展至Eduardo's answer

$ env -i bash -c 'printf "%s\n" "${?+?=$?}" "${#+#=$#}" "${*+*=$*}" "${@+@=$@}" "${-+-=$-}" "${!+!=$!}" "${_+_=$_}" "${$+$=$$}"; env'
?=0
#=0

-=hB

_=bash
$=26927
PWD=/home/username/INVENTORY
SHLVL=1
_=/usr/bin/env

换句话说,以下变量是在使用env -i 运行的脚本中定义的env 显示:

  • $PWD(工作目录)
  • $SHLVL(壳内壳数)
  • $_(上一条命令的最后一个参数)

定义了以下变量,但没有env显示:

  • $?(最后一条命令的结果)
  • $#(参数数量)
  • $-(传递给脚本的标志)
  • $$(脚本的 PID)

【讨论】:

  • env -i bash -c 是完美的!我在清理所有其他东西的同时获得了默认环境,谢谢!
  • 您不需要保存/恢复$?$# 等。这些实际上并不是环境的一部分——它们是内部shell 变量。
【解决方案5】:

您可以使用env 和包装脚本:

#!/bin/bash
env -i /path/to/main_script.sh

来自man env

   -i, --ignore-environment
          start with an empty environment

当然,如果您手动运行脚本,您也可以将脚本运行为env -i script.sh。不幸的是,据我所知,不能像这样使用脚本 shebang 运行bashenv;根据定义,shebang 只能接受内核解析的两个参数。

我能想到的另一个使用envexec -c(几乎相同)的半可靠解决方案是使用exec -c $0 在干净的环境中重新运行脚本,如果您检测到它不干净。假设$HOME 设置在一个不干净的环境中并且没有设置在一个干净的环境中(在我的安装中是这样):

#!/bin/bash
[ "$HOME" != "" ] && exec -c $0
# rest of the script here

【讨论】:

  • 我喜欢exec -c。以一些脆性为代价,您可以将其加强为:[ "$(env | /bin/sed -r -e '/^(PWD|SHLVL|_)=/d')" ] &amp;&amp; exec -c $0。也就是说,它坚持清除所有内容,除了 bash 似乎自动设置的一些内容。
  • 请注意,通过使用env -iexec,您也会丢失非环境(即未导出的)shell 变量。
  • 至于 shebang 问题:coreutils' env 最近 (version 8.30, released in July 2018) 有一个选项 -S 解决了这个问题:这个选项需要一个字符串,该字符串在空格上分割以形成命令被称为。因此,我们的 shebang 可以写成#!/bin/env -iS /bin/bash。这个选项甚至支持设置变量,这样我们就可以保留一些变量,例如PATH和TERM:#!/bin/env -iS PATH=${PATH} TERM=${TERM} /bin/bash。见the documentation
【解决方案6】:

当我尝试它时,这很有效:

for c in $(set | cut -d '=' -f 1); do unset $c; done

它在 const 变量上产生了错误,但我能够忽略它们。

【讨论】:

  • 我会使用env 而不是set,因为后者在 bash 中也可以打印)。
猜你喜欢
  • 2021-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多