尽可能使用最大参数循环执行命令

Loop executing a command using maximum arguments as possible

我有一个程序可以同时处理 ~256 个文件(编辑:限制由命令行参数数给出);我必须在我拥有的许多文件(超过 100k)上执行它。

为此,我现在使用一个简单的循环,为每个文件一个一个地调用我的程序一次。

FILESLIST="$(find /folder/where/the/files/are/ -name '*.xml' 2>/dev/null)"
FILESTAB=($FILESLIST)

for f in "${FILESTAB[@]}"
do
    ./myProgram $f || break
done

但是为了提高我的处理速度,我需要每次都使用多个文件来使用我的程序,如下所示:

./myProgram path/to/file1.xml path/to/file2.xml ...

我想到了类似下面的东西,但我找不到一个好主意来做这个(见评论):

FILESLIST="$(find /folder/where/the/files/are/ -name '*.xml' 2>/dev/null)"
FILESTAB=($FILESLIST)

while [ ${#FILESTAB[@]} -gt 256 ]
do
    ListOf256FilesNames=$FILETAB[0:256]        # << My problem is to do this
    FILETAB=$FILETAB[256:end] # shifting array # <<   and do this too

    ./myProgram $ListOf256FilesNames  # << this works supposing the 2 lines before works
done

./myProgram $FILESTAB  # do the work for remaining files

有没有类似我想做的事情,或者你有什么想法用其他方式来做这个吗?

假设您的 真实 目标是避免超过操作系统允许的最大数量 space 环境变量和参数,您最好让 findxargs 为您完成这项工作。 (这也避免了当你在批处理中得到一堆异常长的文件名时无意中越过,或者当你有很短的文件名并且可以容纳更多文件时通过 运行 额外的进程浪费 CPU)。


最佳实践:让 find 进行除法

与每个文件名运行一个命令的 -exec ... {} ... \; 不同,-exec ... {} + 将尽可能多的参数放入每个命令行。自 2007 年以来,这是 POSIX 合规的。

find /folder/where/the/files/are -name `*.xml` -exec ./myProgram '{}' +

备选方案:GNU xargs

使用 find -0xargs -0 以与旧工具兼容的方式提供类似的功能:

find /folder/where/the/files/are -name `*.xml` -print0 | xargs -0 ./myProgram

如果你真的想要告诉xargs每次调用传递的参数不超过 256 个,你可以 xargs -n 256 -0 ./myProgram.

次优:正是所要求的

files=()
while IFS= read -r -d '' filename; do
  files+=( "$filename" )
done < <(find /folder/where/the/files/are/ -name '*.xml' -print0)

idx=0
while ((idx=0; idx<${#files[@]}; idx+=256)); do
  ./myProgram "${files[@]:$idx:256}"
done