我遇到了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
Ave*_*yne 10
你原来的路线
rm "$archivedir/*.bz2"
Run Code Online (Sandbox Code Playgroud)
可以重写为
rm "$archivedir"/*.bz2
Run Code Online (Sandbox Code Playgroud)
达到同样的效果.通配符扩展在现有设置中无法正常进行.通过将双引号转移到文件路径的"前端"(这是合法的),可以避免这种情况.
为了扩展这一点,bash在处理引号中的元字符时有相当复杂的规则.一般来说
几乎没有任何内容用单引号解释:
echo '$foo/*.c' => $foo/*.c
echo '\\*' => \\*
Run Code Online (Sandbox Code Playgroud)shell替换在双引号内完成,但文件元字符未扩展:
FOO=hello; echo "$foo/*.c" => hello/*.c
Run Code Online (Sandbox Code Playgroud)反引号内的所有内容都传递给解释它们的子shell.未导出的shell变量未在子shell中定义.所以,第一个命令回显空白,但第二个和第三个回声"再见":
BAR=bye echo `echo $BAR`
BAR=bye; echo `echo $BAR`
export BAR=bye; echo `echo $BAR`
Run Code Online (Sandbox Code Playgroud)(并且要按照你想要的方式打印这需要几次尝试显然是不可能的......)
归档时间: |
|
查看次数: |
48044 次 |
最近记录: |