n 個のファイルを反復処理しますか?

n 個のファイルを反復処理しますか?

やりたいことはかなりシンプルです。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またはを使用する賢い方法があると思います。私は を使用していますが、時々使用します。xargsbashzsh

結論として、私は、2600 個の画像ファイルがある場合、montage を約 13 回または 26 回 (100 ~ 200 ファイルごとに 1 回) 呼び出し、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 (実行可能ファイルへの 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] )

答え3

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/そして翻訳元:

答え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

関連情報