在 bash 中,如何定义“命令范围”变量?

在 bash 中,如何定义“命令范围”变量?

我正在读这个关于 Bash 架构的书其中一位 bash 维护者说道:

对于 shell 函数调用,有不同的变量作用域,并且命令前的赋值语句设置的变量的临时作用域。例如,当这些赋值语句位于 shell 内置命令之前时,shell 必须跟踪解析变量引用的正确顺序,而链接范围允许 bash 做到这一点。

我不知道该怎么做。这会打印出一个空白行:

foo="bar" echo $foo

这会打印出“bar”,但foo命令完成后变量仍然定义,所以我不认为它是“命令范围”:

foo="bar"; echo $foo

如何定义具有命令范围的变量?

答案1

你的第一个猜测是正确的,但你举的例子很糟糕。当 shell 读取命令时

foo=bar echo $foo

它所做的第一件事(或者至少是第一件事之一)是寻找变量引用(如$foo)并对其进行评估。  然后它会处理行的剩余部分。(这可能有点过于简单;请参阅bash(1)或者Bash 参考手册了解详情。)因此,您有命令

回声(没有什么)

运行foo=bar;但为时已晚;已经没有什么可以查看 的值了$foo。您可以使用以下序列演示这一点:

$ foo=oldvalue
$ foo=bar echo "$foo"
oldvalue

foo=bar命令

才是正确方法。以下是一些有效的例子:

foo=bar sh -c 'echo "$foo"'

foo=bar env

(您可能希望通过 来传输该信息grep foo。)

我刚刚注意到你引用的那句话,“当这些赋值语句位于 shell 内置命令之前时,例如……”,这表明内置命令(例如echo)代表一种特殊情况。直观地(至少对我来说)你正在寻找的这个“命令范围”必须通过在子进程中设置环境变量来工作,但不清楚它如何适用于不在子进程中运行的内置命令。没有多少内置命令直接访问环境,它们与 shell 变量的交互有时很神秘。但我又想出了几个可能更符合你要求的例子:

foo=bar eval 'echo $foo'

将显示“bar”,因为的求值被推迟了。它由(内置)命令$foo处理,而不是 shell 的初始解析过程。或者,创建一个名为(例如)的文本文件。将(或)命令放入其中,然后说evalshowme.shecho $fooecho "$foo"

foo=bar . showme.sh

这可能就是你的书中所说的内容,“... shell 必须跟踪解析变量引用的正确顺序...。” shell 以某种方式运行中的命令,使其showme.sh等于foobar然后foo在回到其主要输入(终端)时恢复为先前的值(如果有)。

答案2

这里的问题是变量扩展($foo→值)发生在评估整个命令(放入foo=bar环境,运行echo ...)之前。

它适用于访问环境本身的命令:

foo=bar env | grep ^foo

foo=bar declare -p foo

Bash 实际上没有适合你正在寻找的内容的范围;你需要使用“子进程”技巧来获得一个新的过程命令。(当然,这意味着范围的只读,更改将到达父级...)用于( ... )创建子 shell:

(foo=bar; echo $foo)

相关内容