Itérer sur n fichiers?

8

J'ai quelque chose d'assez simple que je veux faire. Je souhaite utiliser montageun répertoire contenant des milliers d'images, avec très peu d'options, à savoir:

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

... mais ce n'est tout simplement pas suffisant, car il ne capture qu'une centaine d'images à la fois; ni

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

... qui saisit toutes les images en même temps, car le fichier résultant est trop gros pour être analysé.

Ce que je veux faire, c'est répéter quelque chose comme 100 à 200 fichiers à la fois. Je suppose que cela pourrait être implémenté en utilisant une boucle for (?), Mais je suis juste un peu confus sur la façon de le faire. Je suppose qu'il y a probablement une façon intelligente d'utiliser find -execou à xargslaquelle je ne pense pas. J'utilise bash, mais j'utilise zshoccasionnellement.

Donc, en conclusion, je recherche un liner qui, étant donné 2600 fichiers image, appelle le montage environ 13 ou 26 fois (une fois pour 100-200 fichiers), et donné n fichiers, peut être appelé un multiple de n fois .

ixtmixilix
la source
1
Vos fichiers sont-ils tous nommés DSC0100.JPG.svg... DSC2600.JPG.svg?
jw013

Réponses:

6

Une bashméthode, utilisant des fonctionnalités de tableau spéciales; probablement traduisible zshavec quelques modifications:

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
jw013
la source
1
j'ai trouvé que ce peu de script bash est également très extensible. Je viens de l'utiliser pour déplacer des fichiers (16 fichiers par répertoire) et cela a fonctionné du premier coup, ce qui était un peu une surprise. Merci.
ixtmixilix
5

Vous pouvez utiliser des xargs pour cela; malheureusement, il n'est pas possible de combiner -I (pour insérer au milieu d'une ligne de commande) et -L (pour limiter le nombre de fichiers pour un seul appel à l'exécutable). Par conséquent, j'ai créé cette ligne de commande à titre d'exemple (mais méfiez-vous des caractères spéciaux dans les noms de fichiers, ils ne sont pas pris en charge):

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

Supprimez le echosi vous voulez vraiment exécuter la commande.

Mises en garde:

  • les noms de fichiers ne doivent pas contenir d'espaces ou d'autres caractères spéciaux
  • la dernière ligne de montage peut contenir moins de 100 fichiers

Mise à jour:

C'est la boucle for correspondante, qui (j'espère) résout le problème des espaces dans les noms de fichiers:

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

Mise à jour 2: une solution python, qui devrait être à l'abri des caractères spéciaux dans les noms de fichiers

#!/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] )
daniel kullmann
la source
2
Si vous allez recommander d'utiliser lsdans un tuyau pour analyser sa sortie, vous devez également mettre en garde contre les nombreux dangers de le faire bien en évidence et au début pour vous assurer que les gens le voient.
jw013
@ jw013 +1 Oui, c'est certainement une préoccupation. Cependant, sa publication m'a laissé supposer qu'il utilisait des photos directement importées d'un appareil photo numérique, qui ne contiennent aucun caractère spécial. Comment proposeriez-vous de résoudre ce problème?
daniel kullmann du
Oui, il semble que les noms de fichiers soient relativement bénins (donc pas de downvote). Cependant, l'OP n'a pas vraiment précisé à quoi ils ressemblent au-delà *.svg(c'est pourquoi j'ai posté un commentaire sur la question posée). Dans le cas le plus général où vous devez gérer tous les noms de fichiers, vous devez recourir à la globalisation du shell et aux tableaux ou find -print0 | xargs -0constructions. Voir ma réponse pour un exemple de la première.
jw013
@ jw013 Votre réponse est vraiment sympa! Je n'ai jamais pris l'effort d'apprendre comment les tableaux fonctionnent en bash. Peut-être que je devrais.
daniel kullmann
2

Voici une version utilisant xargs qui est sans danger pour n'importe quel nom de fichier, mais nécessite un fichier temporaire pour stocker le nombre. Ajustez le '-n 100' pour ajuster le nombre de fichiers par montage. Vous pouvez également échanger le "printf" avec un "find -print0", mais assurez-vous qu'il ne trouve pas "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
Jander
la source
2

Avec GNU Parallel, vous pouvez faire:

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

Il est bien sûr sûr pour les fichiers avec des caractères spéciaux (comme vous pouvez normalement vous y attendre de GNU Parallel).

Installation minimale

Si vous avez juste besoin de parallèle et que «make» n'est pas installé (peut-être que le système est ancien 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/

Regardez la vidéo d'introduction pour une introduction rapide: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 ou sur http://tinyogg.com/watch/TORaR/ et http://tinyogg.com/watch/hfxKj /

Ole Tange
la source