我正在读这个关于 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 的初始解析过程。或者,创建一个名为(例如)的文本文件。将(或)命令放入其中,然后说eval
showme.sh
echo $foo
echo "$foo"
foo=bar . showme.sh
这可能就是你的书中所说的内容,“... shell 必须跟踪解析变量引用的正确顺序...。” shell 以某种方式运行中的命令,使其showme.sh
等于foo
,bar
然后foo
在回到其主要输入(终端)时恢复为先前的值(如果有)。
答案2
这里的问题是变量扩展($foo
→值)发生在评估整个命令(放入foo=bar
环境,运行echo ...
)之前。
它适用于访问环境本身的命令:
foo=bar env | grep ^foo
foo=bar declare -p foo
Bash 实际上没有适合你正在寻找的内容的范围;你需要使用“子进程”技巧来获得一个新的过程命令。(当然,这意味着范围的只读,不更改将到达父级...)用于( ... )
创建子 shell:
(foo=bar; echo $foo)