У меня есть что-то довольно простое, что я хочу сделать. Я хочу использовать montage
в каталоге, содержащем тысячи изображений, с очень небольшим количеством опций, а именно:
me@home$ montage -size 256x256 DSC01*.JPG.svg output.png
...но этого недостаточно, так как он захватывает только около 100 изображений за раз; ни то, ни другое не
me@home$ montage -size 256x256 *.svg output.png
...который захватывает все изображения одновременно, поскольку полученный файл слишком велик для анализа.
Что яхотеть сделатьэто перебрать около 100-200 файлов за раз. Я думаю, это можно реализовать с помощью цикла for (?), но я просто немного запутался в том, как это сделать. Я думаю, что, вероятно, есть умный способ использовать find -exec
or xargs
, о котором я не думаю. Я использую bash
, но я использую zsh
иногда.
Итак, в заключение, я ищу однострочный код, который при наличии 2600 файлов изображений вызовет монтаж примерно 13 или 26 раз (по одному разу на каждые 100-200 файлов), а при наличии n файлов может быть вызван кратно n раз.
решение1
Метод bash
, использующий специальные возможности массива; вероятно, zsh
с некоторыми изменениями его можно перевести в:
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
решение2
Для этого можно использовать xargs; к сожалению, невозможно объединить -I (для вставки в середину командной строки) и -L (для ограничения количества файлов для одного вызова исполняемого файла). Поэтому я создал эту командную строку в качестве примера (но будьте осторожны со специальными символами в именах файлов, они не поддерживаются):
ls . | \
xargs -n 100 echo | \
(a=1;
while read args; do
echo montage -size 256x256 $args output-$a.png;
a=$((a+1));
done
)
Удалите, echo
если вы действительно хотите выполнить команду.
Предостережения:
- имена файлов не должны содержать пробелов и других специальных символов
- в последней строке монтажа может быть менее 100 файлов
Обновлять:
Вот соответствующий цикл for, который (я надеюсь) решает проблему с пробелами в именах файлов:
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
Обновление 2:Решение на Python, которое должно быть устойчиво к специальным символам в именах файлов.
#!/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] )
решение3
С помощью GNU Parallel вы можете:
parallel -N200 montage -size 256x256 {} output{#}.png ::: *.svg
Конечно, это безопасно для файлов со специальными символами (чего обычно и можно ожидать от GNU Parallel).
Минимальная установка
Если вам просто нужен parallel и у вас не установлен «make» (возможно, система старая или 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/
Посмотрите вступительное видео для краткого ознакомления: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1или в http://tinyogg.com/watch/TORaR/иhttp://tinyogg.com/watch/hfxKj/
решение4
Вот версия с использованием xargs, которая безопасна для любого имени файла, но требует временного файла для хранения счетчика. Отрегулируйте '-n 100', чтобы настроить количество файлов на монтаж. Вы также можете заменить "printf" на "find -print0", но убедитесь, что он не найдет "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