rm无法通过通配符从脚本中删除文件,但是从shell提示符开始工作

EMP*_*EMP 54 linux bash shell

我遇到了Linux shell脚本的一个非常愚蠢的问题.我想在目录中删除扩展名为".bz2"的所有文件.在我打电话的脚本中

rm "$archivedir/*.bz2"
Run Code Online (Sandbox Code Playgroud)

其中$ archivedir是目录路径.应该很简单,不应该吗?不知何故,它设法失败并出现此错误:

rm: cannot remove `/var/archives/monthly/April/*.bz2': No such file or directory
Run Code Online (Sandbox Code Playgroud)

但是,在该目录名为test.bz2一个文件,如果我改变我的脚本

echo rm "$archivedir/*.bz2"
Run Code Online (Sandbox Code Playgroud)

并将该行的输出复制/粘贴到终端窗口中,成功删除该文件.我究竟做错了什么?

Dou*_*oug 104

TL; DR

仅引用变量,而不是通配符的整个预期路径

rm "$archivedir"/*.bz2
Run Code Online (Sandbox Code Playgroud)

说明

  • 在Unix中,程序通常不会自己解释通配符.shell解释不带引号的通配符,并用匹配文件名列表替换每个通配符参数.如果$ archivedir可能包含空格,那么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

  • 哇,我不知道shell执行通配符操作而不是实际的文件系统程序.这很好知道! (3认同)
  • 当当前用户不允许列出该目录中的文件时,运行“sudo rm /var/lib/OnlyRootCanList/*”将不起作用。在这种情况下, find 命令会更好地工作。例如`查找。-name "*.jpg" | xargs rm` (2认同)

Ave*_*yne 10

你原来的路线

rm "$archivedir/*.bz2"
Run Code Online (Sandbox Code Playgroud)

可以重写为

rm "$archivedir"/*.bz2
Run Code Online (Sandbox Code Playgroud)

达到同样的效果.通配符扩展在现有设置中无法正常进行.通过将双引号转移到文件路径的"前端"(这是合法的),可以避免这种情况.


Cha*_*tin 9

为了扩展这一点,bash在处理引号中的元字符时有相当复杂的规则.一般来说

(并且要按照你想要的方式打印这需要几次尝试显然是不可能的......)