【问题标题】:Loop executing a command using maximum arguments as possible尽可能使用最大参数循环执行命令
【发布时间】:2018-01-16 05:32:36
【问题描述】:

我有一个可以同时处理 ~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 ...

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

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

有没有我想做的事情,或者你有什么想法用另一种方式来做?

【问题讨论】:

  • Using Find。这讨论了正确将结果读取到数组中(您在上面使用的方法会因带有空格、换行符、可扩展 glob 表达式等的文件名而严重失败)。
  • 顺便说一句,您是否有理由一次执行 256 个批次,而不是让 xargs 将您的列表拆分为可行的最大可能批次大小?
  • 哦,告诉我更多关于这个的(我不知道这种使用xargs的事情)
  • 顺便说一句,见pubs.opengroup.org/onlinepubs/9699919799/basedefs/…,第四段,变量命名约定——全大写的名称由对操作系统或shell有意义的变量使用,而命名空间至少有一个小写-保证应用程序可以安全使用大小写字符,而不会干扰系统行为。

标签: arrays shell loops command-line-arguments


【解决方案1】:

假设您的真正目标是避免超出操作系统允许的环境变量和参数的最大空间量,您最好让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 传递不超过 256 个参数。

次优:正是要求的内容

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

【讨论】:

  • 有趣的查找/执行选项;事实上,对于我的问题,我的程序有一个第一个参数(总是相同的,字符串类型),你认为这种事情会起作用:find /folder/where/the/files/are -name `*.xml` -exec ./myProgram 'myFirstArgument {}' + ?
  • 引用有点错误。 ./myProgram 'myFirstArgument' {} + 很好。 {} 需要是它自己的论点,+ 也是如此。
  • 您想使用 -L 选项将 xargs 限制为 256
  • @glennjackman,那是 如果 OP 实际上关心数字 256。我相信已经确定他们不关心;请参阅有关该问题的 cmets,尤其是 stackoverflow.com/questions/45571833/…(在它作为回复的评论的上下文中)。
  • @glennjackman @charles-duffy 是的,256 不是真正的问题,我想我会重命名帖子(这个数字是由于允许的最大命令行参数数); -n 允许指定要获取的元素数量?
猜你喜欢
  • 2014-01-09
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
  • 2017-06-01
  • 2020-11-04
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
相关资源
最近更新 更多