Tengo algo bastante simple que quiero hacer. Quiero usar montage
en un directorio que contiene miles de imágenes, con muy pocas opciones, a saber:
me@home$ montage -size 256x256 DSC01*.JPG.svg output.png
...pero eso no es suficiente, ya que sólo captura unas 100 imágenes a la vez; tampoco es
me@home$ montage -size 256x256 *.svg output.png
...que captura todas las imágenes al mismo tiempo, ya que el archivo resultante es demasiado grande para analizarlo.
Lo que yoquiero haceres iterar sobre entre 100 y 200 archivos a la vez. Supongo que esto podría implementarse usando un bucle for (?), pero estoy un poco confundido acerca de cómo hacerlo. Supongo que probablemente haya una forma inteligente de usarla find -exec
o xargs
en la que no estoy pensando. Estoy usando bash
, pero lo uso zsh
ocasionalmente.
Entonces, en conclusión, estoy buscando una línea única que, dados 2600 archivos de imagen, llame al montaje aproximadamente 13 o 26 veces (una por cada 100-200 archivos), y dados n archivos, pueda llamarse múltiplo de n veces. .
Respuesta1
Un bash
método que utiliza características especiales de matriz; probablemente traducible zsh
con alguna modificación:
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
Respuesta2
Puedes usar xargs para eso; desafortunadamente, no es posible combinar -I (para insertar en medio de una línea de comando) y -L (para limitar la cantidad de archivos para una sola llamada al ejecutable). Por lo tanto, creé esta línea de comando como ejemplo (pero tenga cuidado con los caracteres especiales en los nombres de archivos, no son compatibles):
ls . | \
xargs -n 100 echo | \
(a=1;
while read args; do
echo montage -size 256x256 $args output-$a.png;
a=$((a+1));
done
)
Elimine el echo
si realmente desea ejecutar el comando.
Advertencias:
- Los nombres de archivos no pueden contener espacios ni otros caracteres especiales.
- la última línea de montaje puede tener menos de 100 archivos
Actualizar:
Este es el bucle for correspondiente, que (espero) resuelva el problema con los espacios en los nombres de los archivos:
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
Actualización 2:Una solución de Python, que debería ser inmune a los caracteres especiales en los nombres de archivos
#!/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] )
Respuesta3
Con GNU Parallel puedes hacer:
parallel -N200 montage -size 256x256 {} output{#}.png ::: *.svg
Por supuesto, es seguro para archivos con caracteres especiales (como normalmente se puede esperar de GNU Parallel).
Instalación mínima
Si solo necesita paralelo y no tiene instalado 'make' (tal vez el sistema sea antiguo o 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/
Mire el vídeo de introducción para una introducción rápida: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1o en http://tinyogg.com/watch/TORaR/yhttp://tinyogg.com/watch/hfxKj/
Respuesta4
Aquí hay una versión que usa xargs que es segura para cualquier nombre de archivo, pero requiere un archivo temporal para almacenar el recuento. Ajuste '-n 100' para ajustar cuántos archivos por montaje. También puede intercambiar "printf" con "find -print0", pero asegúrese de que no encuentre "count.temp".
echo 1 >count.temp
printf "%s\0" *.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