【问题标题】:Improve execution of for cycle改进for循环的执行
【发布时间】:2014-12-09 19:15:44
【问题描述】:

我已经完成了一个小批量脚本来调整(动态)一些图像的大小:

for a in *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP} ;
do convert "$a" -resize $re "$re""_tmp/${a%.*} ["$re"].jpg" ; done

它运行。

问题:如果目录中只有(一个实例).png 文件,脚本会运行但会显示一些错误,因为没有其他文件扩展名(PNG,jpg ,JPG,jpeg,JPEG,bmp,BMP)

改善它的最佳方法是什么?将stderr 重定向到/dev/null?任何想法?我想检查 ($?) 脚本的退出状态,添加 if/then 以显示脚本是否正确运行。

【问题讨论】:

  • 你的意思是“运行正确”?你的意思是“转换任何文件”吗?你的意思是“每个文件转换成功”?还有别的意思吗?

标签: bash glob


【解决方案1】:

我想到了两个简单的解决方案。

shopt builtin 使用nullglob 选项,这样不匹配的glob 就会消失,而不是保留文字。

$ ls *.foo
ls: *.foo: No such file or directory
$ echo one *.foo two
one *.foo two
$ shopt -s nullglob
$ echo one *.foo two
one two

所以你的脚本会变成这样。

shopt -s nullglob
for a in *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP} ;
do convert "$a" -resize $re "$re""_tmp/${a%.*} ["$re"].jpg" ; done

或者在使用 convert 之前测试文件是否存在。

for a in *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP} ;
do [ -f "$a" ] && convert "$a" -resize $re "$re""_tmp/${a%.*} ["$re"].jpg" || :; done

【讨论】:

    【解决方案2】:

    我想澄清一下为什么您的脚本没有按预期工作,并添加另一种可能性以防万一。

    您为什么会看到这些错误?

    这是制作for 循环的一般方法:

    for name [ [ in [ word ... ] ] ; ] do list ; done
    

    在您的代码中,word*.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP},假设您只有 .png 文件,它的扩展如下:

    • Brace Expansion:

      *.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP
      
    • Filename Expansion:

      file1.png file2.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP
      
    • 示例

      $ ls
      file1.png  file2.png
      $ echo *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP}
      file1.png file2.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP
      

    在这一步,这些是您将一一分配给变量 name 的字符串。
    例如:$name -> *.JPG


    使用The Shopt Builtin 改进扩展

    作为第一个建议,您可以使用nocaseglob

    如果设置,Bash 在执行文件名扩展时以不区分大小写的方式匹配文件名。

    使用此选项,您可以将word 减少到*.{png,jpg,jpeg,bmp}

    • 示例

      $ shopt -s nocaseglob
      $ echo *.{png,jpg,jpeg,bmp}
      file1.png file2.png *.jpg *.jpeg *.bmp
      

      甚至*.{PNG,jpg,jpeg,bmp}

      $ echo *.{PNG,jpg,jpeg,bmp}
      file1.png file2.png *.jpg *.jpeg *.bmp
      

    最后,正如@Etan 建议的那样,您可以使用nullglob 选项:

    如果设置,Bash 允许不匹配文件的文件名模式扩展为空字符串,而不是它们本身。

    • 示例

      $ shopt -s nullglob
      $ echo *.{png,jpg,jpeg,bmp}
      file1.png file2.png
      

    在这种情况下,作为nullglob 的替代方案,您可以使用extglob 选项(有时默认启用):

    如果设置,则启用扩展模式匹配功能。

    这些是extended pattern matching features

    ?(pattern-list)
        Matches zero or one occurrence of the given patterns.
    *(pattern-list)
        Matches zero or more occurrences of the given patterns.
    +(pattern-list)
        Matches one or more occurrences of the given patterns.
    @(pattern-list)
        Matches one of the given patterns.
    !(pattern-list)
        Matches anything except one of the given patterns.
    

    所以你可以把word写成*.*(png|jpg|jpeg|bmp)

    • 示例

      $ shopt -u nullglob
      $ shopt -s extglob
      $ echo *.+(png|jpg|jpeg|bmp)
      file1.png file2.png
      

    这样,在Filename Expansion这一步就全部展开了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      • 2016-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多