遍历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个文件一次),给定n个文件,可以被称为n次的倍数。


1
您的文件全部都命名为DSC0100.JPG.svg... DSC2600.JPG.svg吗?
jw013

Answers:


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(用于限制对可执行文件的单次调用的文件数量)组合在一起。因此,我以创建此命令行为例(但是请注意文件名中的特殊字符,不支持它们):

 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 2012年

@ jw013 +1是的,这绝对是一个问题。但是,他的帖子让我假设他正在使用直接从数码相机导入的照片,这些照片不包含任何特殊字符。您将如何建议解决该问题?
丹尼尔·库尔曼2012年

是的,看起来文件名相对不错(因此没有downvote)。但是,OP并没有真正指定它们的外观*.svg(这就是为什么我在询问问题时发表评论)。在最常见的情况下,您需要处理所有文件名,则必须诉诸于shell遍历和数组或find -print0 | xargs -0构造。请参阅我的答案以获取前者的示例。
jw013 2012年

@ jw013您的回答非常好!我从不花力气去学习数组如何在bash中工作。也许我应该。
丹尼尔·库尔曼2012年

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 /

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.