awk e newlines nos dados de entrada

3

Eu quero encontrar arquivos em um diretório e identificar pelo tipo MIME, não pela extensão dos arquivos.

Estou usando este comando para determinar o tipo de mime:

% find . -type f -print0 | xargs -0 -I{} file --mime-type {}
./foo
bar.png: image/png
./OWoHp.png: image/png
./J7ZwV.png: image/png
./foo.txt: inode/x-empty
./bar: inode/x-empty
./hUXnc.png: image/png

O primeiro arquivo tem uma nova linha no nome do arquivo:

% ls foo$'\n'bar.png
foo?bar.png

Tudo bem e o arquivo não deve ser renomeado .

Com o próximo comando, quero filtrar todos os arquivos que não são imagens.

% find . -type f -print0 | xargs -0 -I{} file --mime-type {} | awk -F$"
% find . -type f -print0 | xargs -0 -I{} file --mime-type {} | awk -F$"
./foo
bar.png
" -F":" '/image/ {print $1}' | xargs -I{} identify -format "%[fx:w*h] %i\n" {} identify: unable to open image 'bar.png': No such file or directory @ error/blob.c/OpenBlob/2709. identify: unable to open file 'bar.png' @ error/png.c/ReadPNGImage/3922. 26696 ./OWoHp.png 47275 ./J7ZwV.png 37975 ./hUXnc.png
" -F": " '/image/ {print $1}' bar.png ./OWoHp.png ./J7ZwV.png ./hUXnc.png

e identifique seus tamanhos:

% find . -type f -print0 | xargs -0 -I{} file --mime-type {}
./foo
bar.png: image/png
./OWoHp.png: image/png
./J7ZwV.png: image/png
./foo.txt: inode/x-empty
./bar: inode/x-empty
./hUXnc.png: image/png

Mas isso não funciona porque não há arquivo com o nome bar.png . O nome correto é

% ls foo$'\n'bar.png
foo?bar.png

com uma nova linha no nome.

    
por A.B. 28.06.2015 / 14:37

3 respostas

2

Você pode usar a construção -exec sh -c '...' com find :

find . -type f -exec sh -c 'file --brief --mime-type "$0" | \
grep -q ^image/ && identify -format "%[fx:w*h] %i\n" "$0"' {} \;

ou com exiftool :

exiftool -q -if '$mimetype =~ /image/' -p '$megapixels $directory/$filename' -r .
    
por 28.06.2015 / 18:08
4

Eu acho que sua melhor aposta será usar um loop de shell ao invés de xargs: Então você pode controlar como os comandos são enviados ao argumento do nome do arquivo.

find . -type f -print0 | 
while IFS= read -rd "" filename; do
    type=$( file --brief "$filename" )
    if [[ $type == *image* ]]; then
        identify -format "%[fx:w*h] %i\n" "$filename"
    fi
done
    
por 28.06.2015 / 15:42
2

Como a Steeldriver apontou, seu problema não é awk , é file . Não há NUL na entrada que você está dando para awk porque file o usou. Eu faria essa coisa toda no shell:

find . -type f -print0 | while IFS= read -r -d '' file; do 
    file --mime-type "$file" | grep -qP "\bimage/" && 
        printf '%s %s
find . -type f -print0 | while IFS= read -r -d '' file; do 
    file --mime-type "$file" | grep -qP "\bimage/" && 
        printf '%s %s%pre%' $(identify -format '%[fx:w*h]' "$file") "$file";
done | sort -gz | tr '%pre%' '\n'
256 ./file 10
256 ./file 15
484 ./file 16
576 ./file 11
576 ./file 17
1024 ./file 12
1024 ./file 19
2304 ./file 13
5625 ./file 14
15190 ./file 2
15680 ./file 1
16384 ./file 9
65536 ./file 18
145200 ./file 0
183531 ./file 6
364807 ./file
3
364807 ./file 4
364807 ./file 5
388245 ./file 8
550560 ./file 7
' $(identify -format '%[fx:w*h]' "$file") "$file"; done | sort -gz | tr '%pre%' '\n' 256 ./file 10 256 ./file 15 484 ./file 16 576 ./file 11 576 ./file 17 1024 ./file 12 1024 ./file 19 2304 ./file 13 5625 ./file 14 15190 ./file 2 15680 ./file 1 16384 ./file 9 65536 ./file 18 145200 ./file 0 183531 ./file 6 364807 ./file 3 364807 ./file 4 364807 ./file 5 388245 ./file 8 550560 ./file 7

Eu incluí sort , pois suponho que você esteja tentando melhorar sua resposta aqui . O exemplo acima foi executado em nomes de arquivos com espaços e um ( file\n3 com uma nova linha). Por algum motivo, identify não imprime printf linhas terminadas, então usei %code% .

    
por 28.06.2015 / 15:50

Tags