我一直试图让for循环同时运行一堆命令,并试图通过子shell进行。我设法凑齐下面的脚本进行测试,似乎工作正常。
#!/bin/bash
for i in {1..255}; do
(
#commands
)&
done
wait
唯一的问题是我的实际循环将是for i in files *然后它只是崩溃,我假设因为它启动了太多的子shell来处理。所以我添加了
#!/bin/bash
for i in files*; do
(
#commands
)&
if (( $i % 10 == 0 )); then wait; fi
done
wait
现在失败了。有没有人知道这方面的方法?要么使用不同的命令来限制子壳的数量,要么为$ i提供一个数字?
干杯
答案 0 :(得分:5)
另一种解决方案是使用专为并发而设计的工具:
printf '%s\0' files* | xargs -0 -P6 -n1 yourScript
-P6
是xargs
将启动的最大并发进程数。如果你愿意,可以打10。
我建议xargs
,因为它可能已经存在于您的系统中。如果您想要一个非常强大的解决方案,请查看GNU Parallel。
对于您的问题明确的另一个答案:将计数器作为数组索引?
files=( files* )
for i in "${!files[@]}"; do
commands "${files[i]}" &
(( i % 10 )) || wait
done
(复合命令周围的括号并不重要,因为后台作业与使用子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*
答案 1 :(得分:4)
您可以发现使用jobs
来计算作业数量非常有用。 e.g:
wc -w <<<$(jobs -p)
所以,你的代码看起来像这样:
#!/bin/bash
for i in files*; do
(
#commands
)&
if (( $(wc -w <<<$(jobs -p)) % 10 == 0 )); then wait; fi
done
wait
正如@chepner建议:
在bash 4.3中,您可以在任何作业完成后立即使用wait -n
,而不是等待所有
答案 2 :(得分:3)
明确定义计数器
#!/bin/bash
for f in files*; do
(
#commands
)&
(( i++ % 10 == 0 )) && wait
done
wait
无需初始化i
,因为它会在您第一次使用时默认为0。还没有必要重置该值,因为对于i = 10,20,30等,i %10
将为0
答案 3 :(得分:2)
如果您的Bash≥4.3,则可以使用wait -n
:
#!/bin/bash
max_nb_jobs=10
for i in file*; do
# Wait until there are less than max_nb_jobs jobs running
while mapfile -t < <(jobs -pr) && ((${#MAPFILE[@]}>=max_nb_jobs)); do
wait -n
done
{
# Your commands here: no useless subshells! use grouping instead
} &
done
wait
如果您没有wait -n
,则可以使用以下内容:
#!/bin/bash
set -m
max_nb_jobs=10
sleep_jobs() {
# This function sleeps until there are less than $1 jobs running
local n=$1
while mapfile -t < <(jobs -pr) && ((${#MAPFILE[@]}>=n)); do
coproc read
trap "echo >&${COPROC[1]}; trap '' SIGCHLD" SIGCHLD
[[ $COPROC_PID ]] && wait $COPROC_PID
done
}
for i in files*; do
# Wait until there are less than 10 jobs running
sleep_jobs "$max_nb_jobs"
{
# Your commands here: no useless subshells! use grouping instead
} &
done
wait
这样做的好处是,我们不会对完成工作所花费的时间做出任何假设。只要有足够的空间,就会启动一项新工作。而且,它都是纯粹的Bash,所以不依赖于外部工具和(可能更重要的是),你可以使用你的Bash环境(变量,函数等)而不导出它们(数组可以&#39 ; t很容易导出,这可能是一个巨大的专业人士。)