在 bash for 循环中列出多种文件类型

OB7*_*OB7 5 bash bash-scripting

我写了一个脚本来转换文件夹中的图像。该脚本使用 for 循环:

我=“1”
对于 *.jpg 格式的文件;做
     outputFile=$(echo "image"$(echo $i))
     转换 "$file" -resize 50x50 $outputFile
     i=$[i+1]
完毕

我想要做的是允许脚本在多个文件类型扩展名上运行。现在我试过这样做:

对于 *.jpg *.JPG *.jpeg 格式的文件;做
....
完毕

我遇到的问题是,如果您在一个包含所有 *.JPG 而没有 *.jpg 的文件夹中,即使没有图像,脚本仍然会碰撞 i+1,因为它无论如何都会运行 for 循环,但找不到任何 *.jpg 都会转到 *.JPG。

如何定位多个文件扩展名而不按类型自行运行?例如,它们的语法是这样的:

用于 [*.jpg | 中的文件 *.JPG]; 做
...

?
这样我的输出文件夹总是包含像这样标记的图像:
image1.jpg
image2.jpg
image3.jpg
等等。而不是以

一个文件夹缺少 image1.jpg 结束,因为它没有 *.jpg 首先运行。

Joh*_*024 7

解决方案

使用 nullglob。将以下行放在for循环之前:

shopt -s nullglob
Run Code Online (Sandbox Code Playgroud)

nullglob意味着如果没有这样的文件,则从列表中删除 glob。在没有 nullglob 的情况下观察:

$ echo  *.jpg *.JPG *.jpeg
test.jpg *.JPG *.jpeg
Run Code Online (Sandbox Code Playgroud)

现在,使用 nullglob:

$ shopt -s nullglob
$ echo  *.jpg *.JPG *.jpeg
test.jpg
Run Code Online (Sandbox Code Playgroud)

修改脚本

完整的脚本可能是:

i=1
shopt -s nullglob
for file in *.jpg *.JPG *.jpeg; do
     convert "$file" -resize 50x50 "image$i.jpg"
     i=$((i+1))
done
Run Code Online (Sandbox Code Playgroud)

三注意事项:

  1. 在 的定义中outputFile,所有这些echo陈述都是不必要的。

  2. 按照惯例,我.jpg在输出文件名中添加了扩展名 。如果您真的不想要扩展名,只需将其删除。

  3. $[...]用更标准的形式替换:$((...)).


Sco*_*ott 5

    \n
  1. 由于您想要查找\n多个不同的(不区分大小写)扩展名,\nshopt\xc2\xa0-s\xc2\xa0nullglob答案是一个非常好用的扩展名。

    \n
  2. \n
  3. 如果您只是寻找*.jpg, *.JPG,\n以及其他六种不同的大小写组合,\n最简单的方法是

    \n
     for file in *.[Jj][Pp][Gg]\n
    Run Code Online (Sandbox Code Playgroud)\n

    它查找名称为的文件

    \n
      \n
    • (某事),然后是
    • \n
    • .(句点),然后是
    • \n
    • Jj,然后是
    • \n
    • Pp,然后是
    • \n
    • G或者g
    • \n
    \n

    换句话说,

    \n
      \n
    • (某事),然后是
    • \n
    • .(句点),然后是
    • \n
    • “jpg”,大小写的某种组合
    • \n
    \n
  4. \n
  5. 所以解决你的问题的一种方法是

    \n
     shopt -s nullglob\n for file in *.[Jj][Pp][Gg] *.[Jj][Pp][Ee][Gg]\n do \xe2\x80\xa6\n
    Run Code Online (Sandbox Code Playgroud)\n
  6. \n
  7. 这个[\xe2\x80\xa6]技巧是一个值得了解的技巧,但还有更好的方法。\xc2\xa0\n如果我告诉你有一个名为 的 shell 选项nocaseglob,\n你能猜出它的作用吗?

    \n
     shopt -s nullglob nocaseglob\n for file in *.jpg *.jpeg\n do \xe2\x80\xa6\n
    Run Code Online (Sandbox Code Playgroud)\n

    所以现在*.jpg意味着

    \n
      \n
    • (某事),然后是
    • \n
    • .(句点),然后是
    • \n
    • “jpg”,大小写的某种组合
    • \n
    \n

    因此上面的命令\n将匹配*.jpg, *.JPG, *.Jpg, *.jpeg,*.jPeG等。

    \n
  8. \n
  9. 另一种方法是使用extglobshell 选项\n启用扩展模式匹配运算符。\xc2\xa0\n您仍需要nullglobnocaseglob。\xc2\xa0\n扩展模式匹配运算符都类似于

    \n
    (some_special_character)   (  模式列表  )
    \n

    为了清楚起见,其中添加了空格,\n并且是由 \xc2\xa0 \xc2\xa0 字符分隔的spattern-list列表。\xc2\xa0\n对于您的目的来说,看起来最有趣的是pattern|

    \n
    @(模式列表)
    \n

    这意味着匹配列出的模式之一。\xc2\xa0\n所以现在脚本变成

    \n
    (some_special_character)  (  pattern-list  )
    \n

    这可能看起来需要多输入一些内容,\n但随着扩展数量的增加,权衡也会发生变化。\xc2\xa0 考虑一下,

    \n
    @(pattern-list)
    \n

    \n
     shopt -s nullglob nocaseglob extglob\n for file in *.@(jpg|jpeg)\n do \xe2\x80\xa6\n
    Run Code Online (Sandbox Code Playgroud)\n
  10. \n
  11. 你从哪里学会的$(echo\xc2\xa0\xe2\x80\xa6)?\xc2\xa0\n当然,肯定有用,\n甚至有时,但你过度使用它了。\xc2\xa0\n这很好说$(some_command(s) \xe2\x80\xa6)$(echo \xe2\x80\xa6)

    \n
     for file in *.@(jpg|jpeg|jfif|exif|tif|tiff|gif|bmp|png|svg)\n
    Run Code Online (Sandbox Code Playgroud)\n

    并且您可能甚至不需要引号(在赋值语句中)。

    \n
  12. \n
  13. 好的,你可以原谅这一次,\n因为你知道 的值outputFile是良性的,\n因为你通过非空白、非特殊字符 ( image) 的常量字符串设置它,\n加上一个你设置为的变量\n一个由非空白、非特殊字符 ( 1)\n 组成的常量字符串,并且仅对其进行简单的算术运算。\xc2\xa0\n但是,作为一般规则,您应该始终引用对 shell 变量的所有引用\n,除非您有一个很好的理由不\n并且你确定你知道你在做什么。\xc2\xa0\n所以你的convert命令,理想情况下,应该是

    \n
     for file in *.jpg *.jpeg *.jfif *.exif *.tif *.tiff *.gif *.bmp *.png *.svg\n
    Run Code Online (Sandbox Code Playgroud)\n

    (在 周围加上引号$outputFile。)

    \n
  14. \n
\n