Bash两种间接变量访问方法的差异及循环异常问题
为什么第二个循环仅执行一次?
这个问题的核心在于命令替换的执行流程和IFS的作用时机,咱们一步步拆解两个循环的差异:
第一个循环:for V in ${!var}; do echo $V; done
${!var}是Bash的间接变量扩展,直接把var的值(PATH)当作变量名,展开成PATH的实际内容:foo:bar:baz。- 当这个展开结果进入
for循环的in列表时,Bash会依据当前设置的IFS(这里是:)对字符串做分词处理,把foo:bar:baz拆分成foo、bar、baz三个独立元素,所以循环会执行三次,依次输出每个元素。
第二个循环:for V in $(eval echo \$$var); do echo $V; done
这个循环多了一层命令替换,每一步的行为都和IFS紧密相关:
- Eval解析阶段:
\$$var先展开为\$PATH,eval会把转义的\$还原成普通的$,最终执行的命令是echo $PATH。 - Echo执行阶段:
$PATH展开成foo:bar:baz,因为没有加引号包裹,Bash会按照当前的IFS(:)对这个字符串分词,得到foo、bar、baz三个参数传给echo。而echo的特性是:传入多个参数时,会用空格把它们连接起来输出,所以这一步的输出结果是foo bar baz(末尾带换行)。 - 命令替换捕获阶段:
$(...)会捕获echo的输出,自动去掉末尾的换行符,得到纯字符串foo bar baz。 - For循环分词阶段:现在这个字符串要作为
for循环的in列表,Bash会再次用当前的IFS(:)进行分词。但此时字符串里只有空格,没有:,而空格并不在当前的IFS中(你把IFS设置成了单一的:,覆盖了默认包含空格、制表符、换行的IFS),所以整个foo bar baz会被当作一个完整的元素,循环只执行一次,直接输出整个字符串。
为什么换成空格分隔+默认IFS就正常?
当你把PATH改成空格分隔的内容,且不设置IFS时:
- 第二个循环里的
echo $PATH会把空格分隔的内容分词成多个参数,echo输出依然是空格连接的字符串。 - 此时
for循环使用默认IFS(包含空格),命令替换得到的空格分隔字符串会被拆分成多个元素,循环次数就和第一个循环一致了。
内容的提问来源于stack exchange,提问作者John de Largentaye
相关产品推荐
相关产品推荐

