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提供一个数字?
干杯
另一种解决方案是使用专为并发而设计的工具:
printf '%s\0' files* | xargs -0 -P6 -n1 yourScript
Run Code Online (Sandbox Code Playgroud)
这-P6是xargs将要启动的最大并发进程数.如果你愿意,可以打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)
您会发现使用 来计算作业数量很有用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作业完成后立即继续,而不是等待所有作业