Script de bash para minimizar o PNG continua parando

2

Eu tentei executar este script algumas vezes agora e ele continua pendurado. Eu tenho 60.000 imagens e passa por cerca de 1000 e depois para. Eu tenho executado o comando superior e o processo pngquant desaparece parece. Qualquer ajuda seria muito apreciada.

A última saída que recebi foi

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

E então parou. O script é assim.

#!/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
    
por JediTricks007 29.11.2015 / 09:12

3 respostas

5

A resposta de Rui contém alguns bons conselhos, embora ele parece ter perdido a causa real do fracasso de seu comando. Aparece da saída que você mostra que tem um arquivo chamado ./12/thumbnail/The Official AndreasCY ….png .

Quando você diz

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

é como dizer

for PNG in ./12/thumbnail/112.png ./12/thumbnail/photography.png ./12/thumbnail/Christmas-01.png \
           ./12/thumbnail/OA1920.png ./12/thumbnail/The Official AndreasCY ….png  …

com o resultado de que ./12/thumbnail/The , Official e AndreasCY ser tratado como se fossem nomes de arquivo separados - e, como não são, você recebe o erro que recebeu. Você deve ter muito cuidado ao usar $(…) para gerar uma lista de nomes de arquivos - pelo que quero dizer, evite fazer isso se for possível. find … -exec é uma abordagem muito melhor. No entanto, o comando Rui não funcionará: -exec "Optimized PNG: " falhará porque não existe tal comando como "Optimized PNG: " .

Sugiro que você guarde as seguintes partes da sua resposta original e da resposta de Rui:

#!/bin/sh

cd /var/www/html/wp-content/uploads/2014        (You don’t really need the “/” at the end.)
find . -name '*.png' -type f …

e, em seguida, termine com uma das seguintes opções:

  • -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 {} \; ou
  • -exec myscript {} \;
    onde myscript é

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

Note que você deve sempre citar as variáveis do shell (por exemplo, "$PNG" e "$1" ) a menos que você tenha um bom motivo para não e você está certo de que sabe o que está fazendo. Por contraste, enquanto chaves (por exemplo, ${PNG} ) podem ser importantes, eles não são tão importantes quanto as citações. E, em princípios gerais, sugiro que você use #!/bin/sh a menos que você esteja explicitamente escrevendo um script que dependa de recursos bash, e não funcionará com um shell compatível com POSIX - e eu aconselho contra isso.

    
por 29.11.2015 / 10:51
3

No seu script, a saída de localização é expandida para a linha de comando real, que tem limitações de tamanho. Então, quando os argumentos alimentados pelo find excedem o tamanho, o resto é ignorado.

Este artigo trata de problemas: link

O comando find também é um comando muito potente e tem a opção de invocar comandos, e é uma das maneiras de escapar dessas limitações ao lidar com arquivos grandes.

Você pode executar comandos como este:

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

Onde {} é o arquivo que está sendo manipulado, digite f para definir que você está manipulando um arquivo e $ DIR o diretório base em que o comando está trabalhando recursivamente.

Uma maneira fácil de fazer o que você quer em um liner de linha é:

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

(\ usado para quebrar o comando em duas linhas para adicionar clareza ao post)

Também deixarei aqui um artigo sobre como usar o find juntamente com a opção exec.

link

    
por 29.11.2015 / 09:26
2

A sintaxe globbing pode ser colocada diretamente no loop for. Você não precisa de find . E se você usar globbing diretamente no loop for, não precisará se preocupar com a divisão de palavras, pois o shell cuida disso automaticamente.

Também é uma boa ideia citar suas variáveis de shell quando elas aparecerem nos comandos, ou então elas passarão pela divisão de palavras após a substituição.

Por fim, prefira printf em vez de echo , pois ele se comportará mais corretamente se o nome do arquivo tiver determinados caracteres e for mais portátil em diferentes implementações.

for PNG in *.png; do

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

done

Em zsh e bash com o conjunto de opções relevante , você pode fazer globs recursivas como esta:

for PNG in **/*.png; do

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

done

Isso fará com que a pesquisa caia em subdiretórios, assim como o comando find . No entanto, isso não é padrão POSIX, então se você precisar de algo para trabalhar portável em todos os sistemas parecidos com o POSIX, você deve usar uma das outras respostas.

    
por 29.11.2015 / 17:06

Tags