我遇到了Linux shell脚本的一个非常愚蠢的问题。我想在目录中删除扩展名为“.bz2”的所有文件。在我打电话的脚本中
rm "$archivedir/*.bz2"
其中$ archivedir是目录路径。应该很简单,不应该吗?不知何故,它设法失败并出现此错误:
rm: cannot remove `/var/archives/monthly/April/*.bz2': No such file or directory
但是该目录中有一个名为test.bz2的文件,如果我将脚本更改为
echo rm "$archivedir/*.bz2"
并将该行的输出复制/粘贴到终端窗口中,成功删除该文件。我究竟做错了什么?
TL; DR
仅引用变量,而不是通配符的整个预期路径
rm "$archivedir"/*.bz2
说明
rm $archivedir/*.bz2
可能不会对你做什么rm $archivedir/*.bz2
(没有引号)。在$ archivedir被替换之后发生单词拆分(即,将命令行分解为参数)。因此,如果$ archivedir包含空格,那么您将获得您不想要的额外参数。说archivedir是/var/archives/monthly/April to June
。然后你会得到相当于写rm /var/archives/monthly/April to June/*.bz2
,它试图删除文件“/ var / archives / monthly / April”,“to”,以及所有匹配“June / * .bz2”的文件,这不是你的想。正确的解决方案是写:
rm "$archivedir"/*.bz2
你原来的路线
rm "$archivedir/*.bz2"
可以重写为
rm "$archivedir"/*.bz2
达到同样的效果。通配符扩展在现有设置中无法正常进行。通过将双引号转移到文件路径的“前端”(这是合法的),您可以避免这种情况。
为了扩展这一点,bash在处理引号中的元字符时有相当复杂的规则。一般来说
echo '$foo/*.c' => $foo/*.c
echo '\\*' => \\*
FOO=hello; echo "$foo/*.c" => hello/*.c
BAR=bye echo `echo $BAR`
BAR=bye; echo `echo $BAR`
export BAR=bye; echo `echo $BAR`
(并让它以你想要的方式打印出来 需要多次尝试 显然是不可能的...)
引号导致字符串被解释为字符串文字,尝试删除它们。
从另一个shell脚本调用类似./shell_script.sh的shell脚本时,我发现了类似的错误。这可以通过调用sh shell_script.sh来修复
为什么不只是rm -rf */*.bz2
?在OSX上为我工作。