【问题标题】:Does `bash` have an environment variable stack?`bash` 有环境变量栈吗?
【发布时间】:2022-01-24 19:46:14
【问题描述】:

我很好奇bash 是否有环境变量堆栈。

作为一个用例的例子,它显然是good practice to unset CDPATH in a script。当然,你想在之后恢复 CDPATH 的原始值,这样脚本就不会破坏用户的环境。

如果我们能做到就好了

#!/usr/bin/env bash
pushenv CDPATH
<script here>
popenv CDPATH

然后就这样吧。不幸的是,人们不得不摆弄这些恶作剧:

#!/usr/bin/env bash
old_CDPATH="$CDPATH"
unset CDPATH
<script here>
CDPATH="$old_CDPATH"
unset old_CDPATH

除了凌乱之外,这也是一个真正的问题。如果变量old_CDPATH 可能已经在使用;如果在&lt;script here&gt; 本身中使用$CDPATH,它将中断。

这就是堆栈的用途,也是存在pushdpopd bash 内置函数的原因。但是对于任意变量,我们有类似的内置功能吗?

你可能会说“只在子 shell 中做事,不要导出 old_CDPATH”,我会说,不,有时你必须在同一个 shell 中运行代码(例如源脚本)(例如,如果这些脚本的目的是修改环境变量。

那么,我们如何获得类似堆栈的行为?我们可以用这个成语:

#!/usr/bin/env bash

declare -a arr_old_CDPATH
function do_thing() {
  arr_old_CDPATH+="$CDPATH"
  unset CDPATH
  <script here>
  CDPATH="${arr_old_CDPATH[-1]}"
  unset arr_old_CDPATH[-1]
}
do_thing

我们甚至可以将其打包成poppush 函数:

#!/usr/bin/env bash

function push() { # $1 = stack (array) name, $2 = var name
  local -n arr=$1
  arr+=("${!2}")
  unset "$2"
}

function pop()  { # $1 = stack (array) name
  local -n arr=$1
  echo "${arr[-1]}"
  unset arr[-1]
}

push cdstack CDPATH
<script here>
CDPATH="$(pop CDPATH)"

我们还可以变得更复杂,为每个变量自动创建一个堆栈。然后我们就可以“pop CDPATH”了:


declare _env_stack_name

env_stack_set_name() { # $1 = var name
  local stack_name=_stack_env_$1
  [ -v $stack_name ] || declare -ag $stack_name
  _env_stack_name=$stack_name
}
pushenv() { # $1 = var name
  env_stack_set_name $1
  local -n arr=$_env_stack_name
  arr+=("${!1}")
  unset "$1"
}
popenv() { # $1 = var name  
  env_stack_set_name $1
  local -n arr=$_env_stack_name
  local -n var=$1
  var=${arr[-1]}
  unset arr[-1]
}

pushenv CDPATH
<script here>
popenv CDPATH

对于需要在单个 shell 中运行的复杂脚本所必需的基本堆栈功能而言,这一切似乎都太过分了。

有没有比 pushd/popd 更好的习惯用法或更通用的内置 bash 可以允许推送/弹出环境变量?

【问题讨论】:

  • 不,没有用于环境变量的内置堆栈。

标签: bash


【解决方案1】:

bash 有环境变量栈吗?

没有。

作为一个用例的例子,在脚本中unset CDPATH 显然是一个好习惯。当然,您需要在之后恢复 CDPATH 的原始值,这样脚本就不会破坏用户的环境。

不,为了父进程的利益(包括在父进程是外壳的常见情况下),永远不需要恢复任何环境变量的原始值。没有进程可以更改另一个正在运行的进程的环境,因此被调用的(相对于sourced)脚本对其自身环境的更改对其父进程的环境没有影响。

有时您必须在同一个 shell 中运行代码(例如源脚本)(例如,如果这些脚本的目的是修改环境变量。

是的,但这由执行sourcing 的脚本作者控制。这并不是说环境变量堆栈没有用例,但在实践中,它并不是特别重要的。

【讨论】:

  • 脚本的作者,负责采购。这不是一个答案:“这个用例对我来说并不重要,所以对你来说也不重要”。
  • @Myridium,答案在最上面:“不。” Bash 没有用于变量的内置堆栈。它也没有任何标准的成语,因为无论它对 you 有多重要(对此我没有断言),它对大多数人来说都不是很重要。如果您不喜欢这个答案,我很抱歉,但这就是答案。
  • @Myridium,不过你可能想看看Environment Modules。这不是您所要求的,但它有一些重叠,所以也许它会满足您的目的。
  • “有没有更好的习惯用法 [...] 可以允许推送/弹出环境变量?”
  • 谢谢,环境模块可能有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
相关资源
最近更新 更多