【发布时间】:2018-11-04 07:48:18
【问题描述】:
当我偶然发现这种不一致时,我正在探索在 Bash 中进行间接变量访问的不同方法(macOS 上的 4.4.19 通过 MacPorts):
为什么IFS设置为':'时,下面的第二个循环只循环一次?
注意:IFS 的影响在这里很明显!
#!/usr/bin/env bash
PATH="foo:bar:baz"
var=PATH
IFS=':'
echo ${!var}
# returns foo bar baz
echo $(eval echo \$$var)
# also returns foo bar baz
for V in ${!var}; do
echo $V
done
# returns foo\nbar\nbaz\n
for V in $(eval echo \$$var); do
echo $V
done
# returns foo bar baz
如果您用空格分隔的项目替换 PATH 内容并删除 IFS,它在这两种情况下都可以正常工作。
【问题讨论】:
-
如果输入无效,其中一些案例可能存在安全漏洞。有些没有。
-
比较
var='PATH$(touch /tmp/evil)'时的行为——某些版本(特别是基于eval的版本)将创建/tmp/evil(并且可以代替删除您的主目录或执行任何其他攻击者的操作能够设置var可以选择)。其他人会抛出错误。在这种情况下,哪个更安全是很清楚的。 -
顺便说一句,这里有很多基于引用的错误。通过shellcheck.net 运行您的代码会找到它们;另见BashPitfalls #14。
-
...相比之下,在
for V in ${!var}中,没有echo将您的:s 转换为空格,因此当它们将字符串拆分为多个片段时,它们仍然是冒号for循环遍历,所以循环执行多次。 -
但是如果您将
for V in $(eval echo \$$var); do更改为for V in $(eval "echo \"\$$var\""); do,则行为与其他形式相同,但存在额外的安全漏洞。你在这里问的是纯粹引用差异,没有别的。