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ファイルごとに1回)呼び出し、n個のファイルをn回の倍数で呼び出すことができる1つのライナーを探しています。


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 2012

5

そのためにxargsを使用できます。残念ながら、-I(コマンドラインの途中に挿入)と-L(実行可能ファイルへの1回の呼び出しでファイル数を制限する)を組み合わせることはおそらくできません。したがって、次のコマンドラインを例として作成しました(ただし、ファイル名の特殊文字に注意してください。これらはサポートされていません)。

 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はい、それは間違いなく懸念事項です。しかし、彼の投稿では、デジタルカメラから直接インポートされた、特殊文字を含まない写真を使用していたと想定しています。あなたはその問題に取り組むためにどのように提案しますか?
ダニエル・カルマン、

はい、ファイル名は比較的無害なようです(したがって、反対票はありません)。しかし、OPはそれらがどのように見えるかを実際に指定していません*.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 /

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.