rm无法通过通配符从脚本中删除文件,而是通过shell提示符工作
我用Linux shell脚本遇到了一个非常愚蠢的问题。 我想删除目录中所有扩展名为“.bz2”的文件。 在我打电话的剧本里
rm "$archivedir/*.bz2"
其中$ archivedir是一个目录path。 应该很简单,不是吗? 不知怎的,它pipe理失败,这个错误:
rm: cannot remove `/var/archives/monthly/April/*.bz2': No such file or directory
但是在那个目录下有一个名为test.bz2的文件,如果我把脚本改成
echo rm "$archivedir/*.bz2"
并将该行的输出复制/粘贴到terminal窗口中,即可成功删除该文件。 我究竟做错了什么?
TL; DR
只引用variables,而不是通配符的整个预期path
rm "$archivedir"/*.bz2
说明
-
在Unix中,程序通常不会自行解释通配符。 shell解释未加引号的通配符,并用匹配的文件名列表replace每个通配符参数。 如果$ archivedir可能包含空格,那么
rm $archivedir/*.bz2
可能不会执行你的操作 -
您可以通过引用通配符来禁用此过程,使用双引号或单引号,或者在其之前使用反斜杠。 但是,这不是你想要的 – 你想要通配符扩展到它匹配的文件列表。
-
注意写
rm $archivedir/*.bz2
(不含引号)。 分割这个词(即将命令行分解为参数) 在 $ archivedir被replace之后发生。 所以如果$ archivedir包含空格,那么你会得到额外的参数,你不打算。 说archivedir是/var/archives/monthly/April to June
。 然后,您将得到相当于写入rm /var/archives/monthly/April to June/*.bz2
,它试图删除文件“/ var / archives / monthly / April”,“to”以及所有匹配的文件“六月/ *。bz2”,这不是你想要的。
正确的解决办法是写:
rm“$ archivedir”/ *。bz2
只是为了扩大这一点,bash有相当复杂的处理引号中的元字符的规则。 一般来说
-
几乎没有什么是用单引号解释的:
echo '$foo/*.c' => $foo/*.c echo '\\*' => \\*
-
shellreplace在双引号内完成,但文件元字符不扩展:
FOO=hello; echo "$foo/*.c" => hello/*.c
-
反引号内的所有内容都被传递给解释它们的子shell。 未导出的shellvariables未在子shell中定义。 所以,第一个命令回声空白,但第二个和第三个回声“再见”:
BAR=bye echo `echo $BAR` BAR=bye; echo `echo $BAR` export BAR=bye; echo `echo $BAR`
(让这打印你想要的方式在这需要几次尝试显然是不可能的…)
你的原始线
rm "$archivedir/*.bz2"
可以重写为
rm "$archivedir"/*.bz2
达到同样的效果。 通配符扩展在您现有的设置中没有正确发生。 通过将双引号移到文件path的“前面”(这是合法的),可以避免这种情况。
引号导致string被解释为string文字,尝试删除它们。
从另一个shell脚本调用像./shell_script.sh这样的shell脚本时,我看到了类似的错误。 这可以通过调用sh shell_script.sh来解决
有关内部工作的更多信息:请尝试input:
echo "$archivedir/*.bz2"
在shell提示符下。 你会看到它立即展开。 所以根本就不会看到* 相反,这是传递给它的列表。
编辑:我看到你基本上试过。 那么你想做什么,是在该目录中有几个bz2文件时尝试。 然后你会看到效果。