我遇到了一个我觉得很奇怪的问题,我希望有人可以解释一下。我设置了一个简单的bash for循环,它迭代一些数字并复制文件名中每个数字两次的文件。如果不使用${var_name}
,则会失败,但在执行此操作时会成功。这是一个简短的例子,解释了我的意思:
$ touch 123.foo.123bar
$ touch 456.foo.456bar
$ mkdir out
$ for i in {123,456}; do cp $i.foo.$ibar out; done
cp: cannot stat `123.foo.': No such file or directory
cp: cannot stat `456.foo.': No such file or directory
$ for i in {123,456}; do cp ${i}.foo.${i}bar out; done
$ ls out
123.foo.123bar 456.foo.456bar
第一个失败的原因是什么?第二个失败的原因是什么?
答案 0 :(得分:3)
如果你写$ibar
,bash会将其理解为${ibar}
。确实,它应该在哪里结束变量名称? (变量名中不允许使用点,因此$i.
不会导致问题。)
另一种防止问题的方法是使用反斜杠:
cp $i.foo.$i\bar out
答案 1 :(得分:1)
您的第一个示例引用了未定义的变量$ibar
。
第二个明确使用$i
,这是你想要的。
变量名称由bash扩展,直到第一个单词分隔符,因此$i.foo
将被解析为${i}.foo
,因为.
会终止该单词。
但是,$ibar
只会在空白处结束,因此bash会在范围内查找${ibar}
。
答案 2 :(得分:1)
在正常命令中使用双引号(""
)引用带有变量的参数始终是一个好习惯,以防止意外的单词拆分和路径名扩展:
cp "$i.foo.$ibar" out
如果您发现变量与有效变量字符相邻,则首选解决方案始终是使用${}
格式将其隔离。引用(如cp "$i.foo.$i\bar" out
)可能会因实施而产生混淆:
cp "${i}.foo.${i}bar" out
大部分时间使用${}
也不错。