Iterar sobre n arquivos?

8

Eu tenho algo bastante simples que quero fazer. Eu quero usar montage em um diretório que contém milhares de imagens, com muito poucas opções, a saber:

me@home$ montage -size 256x256 DSC01*.JPG.svg output.png

... mas isso não é bom o suficiente, já que só pega cerca de 100 imagens de cada vez; nem é

me@home$ montage -size 256x256 *.svg output.png

... que captura todas as imagens ao mesmo tempo, pois o arquivo resultante é grande demais para ser analisado.

O que eu quero fazer é fazer uma iteração de algo como 100 a 200 arquivos por vez. Eu acho que isso poderia ser implementado usando um loop for (?), Mas estou um pouco confuso sobre como fazer isso. Eu acho que provavelmente há uma maneira inteligente de usar find -exec ou xargs que eu não estou pensando. Estou usando bash , mas uso zsh ocasionalmente.

Então, em conclusão, eu estou procurando por um forro que, dado 2600 arquivos de imagem, chama montagem cerca de 13 ou 26 vezes (uma vez para cada 100-200 arquivos), e dado n arquivos, pode ser chamado um múltiplo de n vezes.

    
por ixtmixilix 12.07.2012 / 14:50

4 respostas

6

Um método bash , usando recursos especiais de matriz; provavelmente traduzível para zsh com alguma modificação:

image_files=(*.svg) # use your own glob expression
n=200               # number of files per command line; adjust to taste
for ((i=0; i < ${#image_files[@]}; i+=n)); do
        montage -size 256x256 "${image_files[@]:i:n}" output-"$i".png
done
    
por 12.07.2012 / 21:32
5

Você pode usar xargs para isso; infelizmente, não é possível combinar -I (para inserir no meio de uma linha de comando) e -L (para limitar o número de arquivos para uma única chamada para o executável). Portanto, criei esta linha de comando como um exemplo (mas tenha cuidado com caracteres especiais em nomes de arquivos, eles não são suportados):

 ls . | \
   xargs -n 100 echo | \
   (a=1; 
    while read args; do 
     echo montage -size 256x256 $args output-$a.png;
     a=$((a+1)); 
    done
   )

Remova o echo se você quiser realmente executar o comando.

Advertências:

  • nomes de arquivos podem não conter espaços ou outros caracteres especiais
  • a última linha de montagem pode ter menos de 100 arquivos

Atualização:

Esse é o loop correspondente, que (espero) resolve o problema com espaços nos nomes de arquivos:

a=0
b=0
lst=
for f in *; do 
  a=$((a+1))
  lst="$lst '$f'"
  if test $a -ge 100; then 
    eval echo montage --args $lst target-$b.png
    b=$((b+1))
    a=0
    lst=
  fi 
done

Atualização 2: Uma solução python, que deve ser imune a caracteres especiais em nomes de arquivos

#!/usr/bin/env python
# iterate.py

"""Usage: 
%prog <number per call> <file pattern> <command prefix> -- <command postfix>
e.g.  %prog 100 "DSC01*.jpg.svg" montage -size 256x256 -- output-%i.png """

import sys,subprocess,glob,os

if len(sys.argv) < 5: 
  print __doc__.replace("%prog", os.path.basename(sys.argv[0]))
  sys.exit(1)

def chunks(l, n): 
  for i in xrange(0, len(l), n): yield l[i:i+n]

num, pattern, args = int(sys.argv[1]), sys.argv[2], sys.argv[3:]
files, idx = glob.glob(pattern), args.index("--")
before, after = args[0:idx], args[idx+1:]

for idx,chunk in enumerate(chunks(files,num)):
  subprocess.call( before + chunk + [s.replace("%i",str(idx)) for s in after] )
    
por 12.07.2012 / 15:13
2

Aqui está uma versão usando xargs que é segura para qualquer nome de arquivo, mas requer um arquivo temporário para armazenar a contagem. Ajuste o '-n 100' para ajustar quantos arquivos por montagem. Você também pode trocar o "printf" por um "find -print0", mas certifique-se de que ele não encontre "count.temp".

echo 1 >count.temp
printf "%s
echo 1 >count.temp
printf "%s%pre%" *.svg | xargs -0 -n 100 sh -c '
    a='cat count.temp'
    montage --blah "$@" output-"$a".png
    let a=a+1
    echo "$a" >count.temp
    '
rm count.temp
" *.svg | xargs -0 -n 100 sh -c ' a='cat count.temp' montage --blah "$@" output-"$a".png let a=a+1 echo "$a" >count.temp ' rm count.temp
    
por 12.07.2012 / 18:14
2

Com o GNU Parallel você pode fazer:

parallel -N200 montage -size 256x256 {} output{#}.png ::: *.svg

É claro que é seguro para arquivos com caracteres especiais (como você pode esperar do GNU Parallel).

Instalação mínima

Se você só precisa de paralelos e não tem 'make' instalado (talvez o sistema é antigo ou Microsoft Windows):

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
mv parallel sem dir-in-your-$PATH/bin/

Assista ao vídeo de introdução para uma introdução rápida: link ou em link e link

    
por 14.03.2013 / 23:10