我有以下文件:
$ ls *.png | egrep -i "am|pm"
output-0 11.42.30 AM.png
output-0 5.10.12 PM.png
....
我想删除它们但出现此错误:
$ ls *.png | egrep -i "am|pm" | while read line; do rm "$line"; done
rm: cannot remove ''$'\033''[0m'$'\033''[01;35moutput-0 11.42.30 AM.png'$'\033''[0m': No such file or directory
rm: cannot remove ''$'\033''[01;35moutput-0 5.10.12 PM.png'$'\033''[0m': No such file or directory
rm: cannot remove ''$'\033''[01;35moutput-1 11.42.30 AM.png'$'\033''[0m': No such file or directory
我的代码有什么问题?
答案1
ls
在脚本和命令行中存在风险。一个问题是 @PerlDuck 评论中描述的,颜色输出的 ANSI 转义序列。我建议使用另一种方法find
创建测试文件
touch 'output-0 11.42.30 AM.png' 'output-0 5.10.12 PM.png' asdf.png
检查
find
命令行是否找到了你期望找到的文件find . -type f -iname "*[ap]m*.png"
并做到
find . -type f -iname "*[ap]m*.png" -delete
如果你不想搜索子目录,请添加
-maxdepth 1
find . -maxdepth 1 -type f -iname "*[ap]m*.png" -delete
检查结果
ls
名称中带有 am、pm、AM、PM 的文件应该被删除,但
asdf.png
并没有被删除。
答案2
如果你真的想要以while read
这种方式使用循环,然后使用 shell glob 并printf
使用空分隔符,例如
printf '%s\0' *.png | grep -zEi 'am|pm' | while IFS= read -r -d '' line; do echo "$line"; done
但是,有几种方法可以bash
直接扩展要删除的文件列表 - 而无需通过管道传输到grep
和while
:
使用简单的 shell glob
rm -- *[ap]m.png *[AP]M.png
或者 - 如果你不介意匹配
.PNG
扩展名 - 使用nocaseglob
选项shopt -s nocaseglob rm -- *[ap]m.png
使用扩展的 glob
shopt -s extglob rm -- *@(AM|PM).png *@(am|pm).png
或者
shopt -s extglob nocaseglob
rm -- *@(am|pm).png
标记--
选项的结束,以防文件名以连字符开头 -./*(am|pm)
如果您愿意,您可以使用带有明确目录前缀的模式。
如果您想在删除之前以交互方式查看文件名,请添加-i
或选项。-I