使用 read line 迭代变量

使用 read line 迭代变量

我有以下文件:

$ 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直接扩展要删除的文件列表 - 而无需通过管道传输到grepwhile

  1. 使用简单的 shell glob

    rm -- *[ap]m.png *[AP]M.png
    

    或者 - 如果你不介意匹配.PNG扩展名 - 使用nocaseglob选项

    shopt -s nocaseglob
    rm -- *[ap]m.png
    
  2. 使用扩展的 glob

    shopt -s extglob
    rm -- *@(AM|PM).png *@(am|pm).png
    

或者

    shopt -s extglob nocaseglob
    rm -- *@(am|pm).png

标记--选项的结束,以防文件名以连字符开头 -./*(am|pm)如果您愿意,您可以使用带有明确目录前缀的模式。

如果您想在删除之前以交互方式查看文件名,请添加-i或选项。-I

相关内容