![是否可以声明一个局部变量而不覆盖子进程的原始变量?](https://linux22.com/image/86420/%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E5%A3%B0%E6%98%8E%E4%B8%80%E4%B8%AA%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E8%80%8C%E4%B8%8D%E8%A6%86%E7%9B%96%E5%AD%90%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%8E%9F%E5%A7%8B%E5%8F%98%E9%87%8F%EF%BC%9F.png)
如果我有一个预先存在的 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
即使local
我declare
在function 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