用于缩小 PNG 的 Bash 脚本不断停止

用于缩小 PNG 的 Bash 脚本不断停止

我已经尝试运行这个脚本几次了,但它一直挂着。我有 60,000 张图像,它经过大约 1000 张后就停止了。我一直在运行 top 命令,进程 pngquant 似乎消失了。任何帮助将非常感激。

我得到的最后一个输出是

Optimized PNG: ./12/thumbnail/112.png
Optimized PNG: ./12/thumbnail/photography.png
Optimized PNG: ./12/thumbnail/Christmas-01.png
Optimized PNG: ./12/thumbnail/OA1920.png
error: cannot open ./12/thumbnail/The for reading
Optimized PNG: ./12/thumbnail/The
error: cannot open Official for reading
Optimized PNG: Official
error: cannot open AndreasCY for reading
Optimized PNG: AndreasCY

然后它就停了。脚本看起来像这样。

#!/bin/bash

cd /var/www/html/wp-content/uploads/2014/

for PNG in $(find . -name '*.png'); do

  pngquant --ext .png --force 256 ${PNG}
  echo "Optimized PNG: ${PNG}"

done

答案1

瑞的回答包含了一些很好的建议,尽管他似乎错过了你的命令失败的真正原因。从输出中可以看出,您有一个名为../12/thumbnail/The Official AndreasCY ….png

当你说

for PNG in $(find . -name '*.png')

这就像说

适用于 ./12/thumbnail/112.png ./12/thumbnail/photography.png ./12/thumbnail/Christmas-01.png \
           ./12/thumbnail/OA1920.png ./12/thumbnail/官方 AndreasCY ….png...

结果./12/thumbnail/TheOfficial、 、 和AndreasCY 被视为单独的文件名,而且,由于它们不是单独的文件名,因此您会得到错误。您应该非常小心地使用它$(…)来生成文件名列表 - 我的意思是,如果可能的话,请避免这样做。  find … -exec是一个更好的方法。然而,Rui 给出的命令不起作用:-exec "Optimized PNG: " 会失败,因为没有这样的命令"Optimized PNG: "

我建议你保留你原来的答案和Rui的答案的以下部分:

#!/bin/sh

cd /var/www/html/wp-content/uploads/2014        (你实际上并不需要末尾的“/”。)
寻找 。 -name '*.png' -type f ...

然后使用以下操作之一完成它:

  • -exec pngquant --ext .png --force 256 {} \; -exec echo "Optimized PNG:" {} \;
  • -exec pngquant --ext .png --force 256 {} \; -printf "Optimized PNG: %p\n"
  • -exec sh -c 'pngquant --ext .png --force 256 "$1"; echo "Optimized PNG: $1"' sh {} \;, 或者
  • -exec myscript {} \;
    哪里myscript

    #!/bin/sh
    pngquant --ext .png --force 256 "$1"
    echo "Optimized PNG: $1"
    

请注意,您应该始终引用 shell 变量(例如"$PNG""$1"),除非您有充分的理由不这样做,并且您当然你知道你在做什么。相比之下,虽然大括号(例如,${PNG})可能很重要,但它们不如引号重要。而且,根据一般原则,我建议您使用,#!/bin/sh 除非您明确编写依赖于 bash 功能的脚本,并且无法与 POSIX 兼容的 shell 一起使用 — 我建议不要这样做。

答案2

在您的脚本中,查找输出被扩展为实际的命令行,该命令行在大小上有限制。因此,当 find 提供的参数超过大小时,其余的将被忽略。

这篇文章涉及有问题的: http://www.cyberciti.biz/faq/argument-list-too-long-error-solution/

find 命令也是一个非常强大的命令,并且有一个调用命令的选项,这是处理大文件时摆脱这些限制的方法之一。

您可以像这样执行命令:

find $DIR -name '*.png' -type f -exec command {} \;

其中 {} 是正在处理的文件,类型 f 是定义您正在处理的文件,$DIR 是命令递归工作的基目录。

在一条生产线中完成您想要的操作的一种简单方法是:

find /var/www/html/wp-content/uploads/2014 . -name '*.png' -type f \ 
-exec pngquant --ext .png --force 256 {} \; -exec echo "Optimized PNG: " {} \;

(\ 用于将命令分成两行以增加帖子的清晰度)

我还将在这里留下一篇关于将 find 与 exec 选项一起使用的文章。

http://linuxaria.com/howto/linux-shell-how-to-use-the-exec-option-in-find-with-examples

答案3

Globbing 语法可以直接放入 for 循环中。你find根本不需要。如果您直接在 for 循环中使用通配符,则不必担心分词,因为 shell 会自动处理这个问题。

当 shell 变量出现在命令中时,引用它们也是一个好主意,否则它们在替换后将进行分词。

最后,更喜欢printf而不是echo,因为如果您的文件名中包含某些字符,它的行为会更正确,并且在不同的实现之间更可移植。

for PNG in *.png; do

  pngquant --ext .png --force 256 "$PNG"
  printf "Optimized PNG: %s\n" "$PNG"

done

在 zsh 和 bash 中以及相关选项集,你可以像这样进行递归 glob:

for PNG in **/*.png; do

  pngquant --ext .png --force 256 "$PNG"
  printf "Optimized PNG: %s\n" "$PNG"

done

这将导致搜索下降到子目录,就像find命令一样。但是,这不是 POSIX 标准,因此如果您需要在所有类似 POSIX 的系统上可移植地工作,您应该使用其他答案之一。

相关内容