bash:使用文件列表限制for循环中的子shell

Nat*_*axe 5 bash for-loop subshell

我一直试图让for循环同时运行一堆命令,并试图通过子shell进行.我设法拼凑下面的脚本进行测试,它似乎工作正常.

#!/bin/bash
for i in {1..255}; do
  (
    #commands
  )&

done
wait
Run Code Online (Sandbox Code Playgroud)

唯一的问题是我的实际循环将用于文件中的i*然后它只是崩溃,我假设因为它启动了太多的子shell来处理.所以我补充道

#!/bin/bash
for i in files*; do
  (
    #commands
  )&
if (( $i % 10 == 0 )); then wait; fi
done
wait
Run Code Online (Sandbox Code Playgroud)

现在失败了.有没有人知道这方面的方法?要么使用不同的命令来限制子壳的数量,要么为$ i提供一个数字?

干杯

koj*_*iro 5

xargs的/并行

另一种解决方案是使用专为并发而设计的工具:

printf '%s\0' files* | xargs -0 -P6 -n1 yourScript
Run Code Online (Sandbox Code Playgroud)

-P6xargs将要启动的最大并发进程数.如果你愿意,可以打10.

我建议xargs因为它可能已经存在于您的系统中.如果您想要一个非常强大的解决方案,请查看GNU Parallel.

数组中的文件名

对于明确问题的另一个答案:获取计数器作为数组索引?

files=( files* )
for i in "${!files[@]}"; do
    commands "${files[i]}" &
    (( i % 10 )) || wait
done
Run Code Online (Sandbox Code Playgroud)

(复合命令周围的括号并不重要,因为后台作业将产生与使用子shell相同的效果.)

功能

只是不同的语义:

simultaneous() {
    while [[ $1 ]]; do
        for i in {1..11}; do
            [[ ${@:i:1} ]] || break
            commands "${@:i:1}" &
        done
        shift 10 || shift "$#"
        wait
    done
}
simultaneous files*
Run Code Online (Sandbox Code Playgroud)


who*_*oan 4

您会发现使用 来计算作业数量很有用jobs。例如:

wc -w <<<$(jobs -p)
Run Code Online (Sandbox Code Playgroud)

所以,你的代码将如下所示:

#!/bin/bash
for i in files*; do
  (
    #commands
  )&
  if (( $(wc -w <<<$(jobs -p)) % 10 == 0 )); then wait; fi
done
wait
Run Code Online (Sandbox Code Playgroud)

正如@chepner所建议的:

在 bash 4.3 中,您可以在任何wait -n作业完成后立即继续,而不是等待所有作业