O redirecionamento precisa ser citado para evitar que o presente shell o interprete.
Mas citando isso também evitará que a saída do comando seja redirecionada.
A solução conhecida para isso é chamar um shell:
find . -name '*.jpg' -exec sh -c 'echo "$1" >"$1".new' called_shell '{}' \;
Nesse caso, o redirecionamento ( >
) é citado no shell atual e funciona corretamente dentro do shell chamado. O called_shell
é usado como o parâmetro $0
(o nome) do shell filho ( sh
).
Isso funciona bem se um sufixo é adicionado ao nome do arquivo, mas não se você usar um prefixo. Para que um prefixo funcione, você precisa remover os ./
encontrados antes dos nomes dos arquivos com ${1#./}
e usar a opção -execdir
.
Você pode (ou não) querer usar a opção -iname
para que os arquivos chamados *.JPG
ou *.JpG
ou outras variações também sejam incluídos.
find . \( -iname '*.jpg' -o -iname '*.jpeg' \) -execdir sh -c '
cjpeg -quality 80 "$1" > optimized_"${1#./}"
' called_shell '{}' \;
E você pode (ou não) também querer chamar o shell uma vez por diretório, em vez de uma vez por arquivo, adicionando um loop ( for f do … ; done
) e um +
no final:
find . \( -iname '*.jpg' -o -iname '*.jpeg' \) -execdir sh -c '
for f; do cjpeg -quality 80 "$f" > optimized_"${f#./}"; done
' called_shell '{}' \+
E, finalmente, como cjpeg
é capaz de gravar diretamente em um arquivo, o redirecionamento pode ser evitado como:
find . \( -iname '*.jpg' -o -iname '*.jpeg' \) -execdir sh -c '
for f; do cjpeg -quality 80 "$f" -outfile optimized_"${f#./}"; done
' called_shell '{}' \+