迭代 n 个文件?

ixt*_*lix 8 shell imagemagick

我有一些我想做的相当简单的事情。我想montage在包含数千张图像的目录上使用,选项很少,即:

me@home$ montage -size 256x256 DSC01*.JPG.svg output.png
Run Code Online (Sandbox Code Playgroud)

...但这还不够好,因为它一次只能抓取大约 100 张图像;既不是

me@home$ montage -size 256x256 *.svg output.png
Run Code Online (Sandbox Code Playgroud)

...同时抓取所有图像,因为生成的文件太大而无法解析。

想要做的是一次迭代 100-200 个文件。我想这可以使用 for 循环 (?) 来实现,但我对如何做到这一点有点困惑。我想可能有一种聪明的使用方法,find -exec或者xargs我没有想到。我正在使用bash,但我zsh偶尔会使用。

所以,总而言之,我正在寻找一种单行,给定 2600 个图像文件,调用蒙太奇大约 13 或 26 次(每 100-200 个文件一次),并且给定 n 个文件,可以调用 n 次的倍数.

jw0*_*013 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
Run Code Online (Sandbox Code Playgroud)


dan*_*ann 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
   )
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

更新 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] )
Run Code Online (Sandbox Code Playgroud)

  • 如果你打算推荐在管道中使用 `ls` 来解析它的输出,你还应该[警告这样做的许多危险](http://mywiki.wooledge.org/ParsingLs) 显着地,并在开始时以确保人们看到它。 (2认同)