find arcana: não consigo fazer o pipe funcionar na linha -exec

4

Como canalizar os resultados de uma descoberta por meio de um sed para xformar o fluxo e usar esse fluxo transformado como um dos dois argumentos para um script? IE:

find mostra file1.tiff (entre outros)
sed transforma file1.tiff - > file1.jpg
um comando é executado usando os dois argumentos: convert file1.tiff file1.jpg

Eu tentei isso de várias maneiras e não consigo. Aqui está uma tentativa que dá o sabor:

find ./out -regex ".*_p[bg]_.*tiff" -exec echo "Processing {}" \; -exec convert {} 'echo {} | sed s/tiff/jpg/' \;

Eu deveria desistir e escrever um script Python para fazer cada uma dessas partes separadamente, mas finalmente estou tentando aprender ferramentas UNIX e agora estou obcecado. Socorro!

    
por shanusmagnus 01.04.2011 / 05:02

2 respostas

8

Não sei se você pode ter um pipe dentro de -exec . find -exec echo {} \| sed s/tiff/jpg \; parece não funcionar.

Se você acha que sua melhor opção é criar um script para fazer a conversão, por exemplo,

convert_tiff_to_jpg :

#!/bin/bash
echo "Processing $1"
convert "$1" "${1/%tiff/jpg}"

e chame-o usando find -exec como você pretendia:

find ./out -regex ".*_p[bg]_.*tiff" -exec convert_tiff_to_jpg {} \;

Existem algumas maneiras de usar find -print0 | xargs -0 , mas todas são bem feias:

find ./out -regex ".*_p[bg]_.*tiff" -print0 |
while IFS= read -d $'
find ./out -regex ".*_p[bg]_.*tiff" -print0 |
while IFS= read -d $'
find ./out -regex ".*_p[bg]_.*tiff" -print0 |
    xargs -0 -I FILE bash -c 'F="FILE"; echo "$F" "${F/%tiff/jpg}"'
' -r filename; do echo "Processing $filename" convert "$filename" "${filename/%tiff/jpg}" done
' -r filename; do echo "Processing $filename" convert "$filename" "$(echo "$filename" | sed 's/tiff$/jpg/')" done

ou

#!/bin/bash
echo "Processing $1"
convert "$1" "${1/%tiff/jpg}"

ou

find ./out -regex ".*_p[bg]_.*tiff" -exec convert_tiff_to_jpg {} \;

Observe que alterei s/tiff/jpg para s/tiff$/jpg , de forma que, se tiff aparecer em qualquer lugar diferente do final do nome do arquivo, ele não será alterado.

    
por 01.04.2011 / 05:12
1

Você está tentando passar um comando shell para -exec , mas o que é preciso é o nome de um programa e uma lista de argumentos. Então você precisa dizer explicitamente para lançar um shell.

find ./out -regex ".*_p[bg]_.*tiff" \
     -exec sh -c 'echo "Processing $0"; convert "$0" "${0%.tiff}.jpg"' {} \;
  • sh -c 'shell code, not using single quotes' é uma expressão relativamente comum quando você precisa de recursos de shell em um contexto que espera um comando com argumentos.
  • -exec sh -c 'do stuff with "$0"' {} \; é um find e idioma do shell. Algumas versões do find permitem escrever o {} diretamente dentro do código shell, mas isso é uma má ideia, não apenas porque algumas versões não o fazem, mas também porque isso pode quebrar horrivelmente se o nome do arquivo contiver caracteres especiais ). Então, em vez disso, o nome do arquivo é passado para o shell como seu 0º argumento, e o script usa a variável do shell $0 para se referir ao arquivo.
  • echo tiff_filename | sed s/tiff/jpg/ é uma maneira complexa, ineficiente, incorreta e frágil de alterar o nome do arquivo. É complexo e ineficiente porque você está chamando sed. Está errado porque você está substituindo tiff em qualquer parte do arquivo: por exemplo, tiffany.tiff se tornaria jpgany.tiff . É frágil porque não funcionaria com alguns nomes de arquivos (algumas implementações de echo mangle backslashes). Em vez disso, use ${0%.tiff} para remover o sufixo .tiff do nome do arquivo em $0 .
por 02.04.2011 / 00:06