Итерировать по n файлам?


8

У меня есть кое-что довольно простое, что я хочу сделать. Я хочу использовать 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или xargsо котором я не думаю. Я использую bash, но я использую zshиногда.

Итак, в заключение, я ищу одну строку, которая, учитывая 2600 файлов изображений, вызывает монтаж около 13 или 26 раз (один раз для каждых 100-200 файлов), и учитывая n файлов, может быть вызвана кратно n раз ,


1
Ваши файлы все названы DSC0100.JPG.svg... DSC2600.JPG.svg?
— jw013

Ответы:


6

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

1
я обнаружил, что этот сценарий bash также очень расширяем. я просто использовал его для перемещения некоторых файлов (16 файлов на каталог), и это сработало с первой попытки, что было немного удивительно. благодарю вас.
— ixtmixilix

5

Вы можете использовать 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] )

2
Если вы собираетесь порекомендовать использовать lsв канале для анализа его выходных данных, вы также должны предупредить о многих опасностях делать это заметно, и в начале, чтобы убедиться, что люди видят это.
— jw013

@ jw013 +1 Да, это действительно проблема. Однако его публикация позволила мне предположить, что он использовал фотографии, импортированные непосредственно с цифровой камеры, которые не содержат специальных символов. Как бы вы предложили решить эту проблему?
— Даниэль Куллманн

Да, похоже, что имена файлов относительно мягкие (следовательно, нет отрицательного голоса). Однако ОП на самом деле не уточнил, как они выглядят за пределами *.svg(именно поэтому я разместил комментарий по поводу вопроса). В наиболее общем случае, когда вам нужно обработать все имена файлов, вам придется прибегнуть к глобализации оболочки и массивам или find -print0 | xargs -0конструкциям. Смотрите мой ответ для примера первого.
— jw013

@ jw013 Ваш ответ действительно хорош! Я никогда не пытался узнать, как работают массивы в bash. Возможно я должен.
— Даниэль Куллманн

2

Вот версия с использованием 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

2

С GNU Parallel вы можете делать:

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

Это, конечно, безопасно для файлов со специальными символами (как обычно можно ожидать от GNU 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. /

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.