是否可以声明一个局部变量而不覆盖子进程的原始变量?

是否可以声明一个局部变量而不覆盖子进程的原始变量?

如果我有一个预先存在的 ENV 变量,是否可以使用原始值在子进程中声明一个新的局部变量?

请记住,我不知道子进程将使用哪些变量。因此,仅保存原始值并进行操作var=original mycmd -with -args是不够的。

# print.sh:
echo "from print.sh: $MY_VAR"

# local.sh:
run () {
  declare MY_VAR="should not be seen"
  bash print.sh
}
MY_VAR="original" run

上面的打印:from print.sh: should not be seen而不是:from print.sh: original即使localdeclarefunction body

我希望declare/local/typeset有一些选项,但我没有找到任何选项:在本地为此变量设置一个值,但子进程使用原始值。

答案1

常见的约定是对环境变量使用全大写,对脚本局部变量使用全小写。这样,局部变量就不会与环境变量发生冲突。

我认为 zsh 没有选项来区分变量的本地值和导出值。解决方法是保存并恢复该值。这确实意味着列出您要保存的变量。

run () {
  typeset -A _saved_variables
  _saved_variables[foo]=$foo _saved_variables[bar]=$bar
  local foo='not seen' bar='not seen either'
  foo=$_saved_variables[foo] bar=$_saved_variables[bar] bash print.sh
}

如果你想保留整个环境,你可以运行typeset -px以可解析的形式打印出来。请注意,如果您导出了只读变量,则此操作将不起作用;要处理这种情况,您需要检查变量名称并仅选择非只读的变量名称。

run () {
  _saved_variables=`typeset -px`
  local foo='not seen' bar='not seen either'
  (eval $_saved_variables; exec bash print.sh)
}

另一种选择是以不同的方式构建脚本。确定要在子 shell 中运行的命令,并将其打印出来(适当引用)以供父 shell 执行。

run () {
  # you can clobber variables here
  printf %q "bash print.sh"
}
eval $(run)

答案2

这个问题是针对 Zsh 的。但是,对于 Bash 和 mksh 用户来说,这是可能的,但需要注意:https://unix.stackexchange.com/a/272576/42107

相关内容