Über n Dateien iterieren?

Über n Dateien iterieren?

Ich möchte etwas ziemlich Einfaches tun. Ich möchte es montagein einem Verzeichnis verwenden, das Tausende von Bildern enthält, und zwar mit sehr wenigen Optionen, nämlich:

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

...aber das ist einfach nicht gut genug, da es nur etwa 100 Bilder auf einmal aufnimmt; weder ist

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

...das alle Bilder gleichzeitig erfasst, da die resultierende Datei zu groß zum Analysieren ist.

Was ichmöchte tunbesteht darin, über etwa 100-200 Dateien gleichzeitig zu iterieren. Ich denke, dies könnte mithilfe einer for-Schleife (?) implementiert werden, aber ich bin einfach ein bisschen verwirrt, wie das geht. Ich denke, es gibt wahrscheinlich eine clevere Möglichkeit, find -execoder zu verwenden xargs, an die ich nicht denke. Ich verwende bash, aber ich verwende zshgelegentlich.

Zusammenfassend suche ich also nach einem Einzeiler, der bei 2600 Bilddateien die Montage etwa 13 oder 26 Mal aufruft (einmal für jeweils 100–200 Dateien) und bei n Dateien ein Vielfaches von n-Mal aufgerufen werden kann.

Antwort1

Eine bashMethode, die spezielle Array-Funktionen verwendet; zshmit einigen Änderungen wahrscheinlich übersetzbar wie folgt:

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

Antwort2

Sie können dafür xargs verwenden; leider ist es nicht möglich, -I (zum Einfügen in die Mitte einer Befehlszeile) und -L (zum Begrenzen der Anzahl der Dateien für einen einzelnen Aufruf der ausführbaren Datei) zu kombinieren. Daher habe ich diese Befehlszeile als Beispiel erstellt (achten Sie jedoch auf Sonderzeichen in Dateinamen, diese werden nicht unterstützt):

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

Entfernen Sie das echo, wenn Sie den Befehl wirklich ausführen möchten.

Vorbehalte:

  • Dateinamen dürfen keine Leerzeichen oder andere Sonderzeichen enthalten
  • Die letzte Montagezeile kann weniger als 100 Dateien enthalten

Aktualisieren:

Dies ist die entsprechende For-Schleife, die (hoffentlich) das Problem mit Leerzeichen in Dateinamen löst:

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

Aktualisierung 2:Eine Python-Lösung, die gegen Sonderzeichen in Dateinamen immun sein sollte

#!/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] )

Antwort3

Mit GNU Parallel können Sie Folgendes tun:

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

Es ist natürlich sicher für Dateien mit Sonderzeichen (wie Sie es normalerweise von GNU Parallel erwarten können).

Minimale Installation

Wenn Sie nur Parallel benötigen und „make“ nicht installiert haben (vielleicht ist das System alt oder 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/

Sehen Sie sich das Einführungsvideo für eine kurze Einführung an: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1oder bei http://tinyogg.com/watch/TORaR/Undhttp://tinyogg.com/watch/hfxKj/

Antwort4

Hier ist eine Version mit xargs, die für jeden Dateinamen sicher ist, aber eine temporäre Datei zum Speichern der Anzahl erfordert. Passen Sie „-n 100“ an, um die Anzahl der Dateien pro Montage anzupassen. Sie können „printf“ auch durch „find -print0“ ersetzen, stellen Sie jedoch sicher, dass „count.temp“ nicht gefunden wird.

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

verwandte Informationen