等待脚本中的bash后台作业完成

mar*_*ark 49 bash scripting job-control

为了最大化CPU使用率(我在EC2中的Debian Lenny上运行)我有一个简单的脚本来并行启动作业:

#!/bin/bash

for i in apache-200901*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200902*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200903*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200904*.log; do echo "Processing $i ..."; do_something_important; done &
...
Run Code Online (Sandbox Code Playgroud)

我对这个工作解决方案非常满意,但是我无法弄清楚如何编写进一步的代码,只有在所有循环完成后才执行.

有没有办法控制这个?

edu*_*ffy 78

有一个bash内置的命令.

wait [n ...]
      Wait for each specified process and return its termination  sta?
      tus.   Each  n  may be a process ID or a job specification; if a
      job spec is given, all processes  in  that  job’s  pipeline  are
      waited  for.  If n is not given, all currently active child pro?
      cesses are waited for, and the return  status  is  zero.   If  n
      specifies  a  non-existent  process or job, the return status is
      127.  Otherwise, the return status is the  exit  status  of  the
      last process or job waited for.
Run Code Online (Sandbox Code Playgroud)

  • 提示使用```wait $(jobs -p)```等待新创建的作业. (21认同)
  • @lambacck不是`wait`,没有相同的参数? (10认同)
  • 或者,如果您还有其他作业作为背景(例如,当您使用Ctrl + Z挂起vim时),请使用`wait $(jobs -rp)`:附加的`-r`标志过滤掉*正在运行的*作业。 (2认同)

Ole*_*nge 27

使用GNU Parallel将使您的脚本更短,可能更高效:

parallel 'echo "Processing "{}" ..."; do_something_important {}' ::: apache-*.log
Run Code Online (Sandbox Code Playgroud)

这将为每个CPU核心运行一个作业,并继续执行此操作,直到处理完所有文件.

您的解决方案基本上会在运行之前将作业分成组.这里有4组32个职位:

简单的调度

GNU Parallel会在完成后生成一个新进程 - 保持CPU处于活动状态,从而节省时间:

GNU并行调度

了解更多:

  • 这个“并行--引用”有点奇怪 (3认同)
  • 谢谢你的平行! (2认同)

sch*_*rer 9

一个最小的例子wait $(jobs -p)

  for i in {1..3}
  do
    (echo "process $i started" && sleep 5 && echo "process $i finished")&
  done  

  sleep 0.1 # For sequential output
  echo "Waiting for processes to finish" 
  wait $(jobs -p)
  echo "All processes finished"
Run Code Online (Sandbox Code Playgroud)

示例输出:

process 1 started
process 2 started
process 3 started
Waiting for processes to finish
process 2 finished
process 1 finished
process 3 finished
All processes finished
Run Code Online (Sandbox Code Playgroud)


Oli*_*nde 5

我最近不得不这样做,最终得到以下解决方案:

while true; do
  wait -n || {
    code="$?"
    ([[ $code = "127" ]] && exit 0 || exit "$code")
    break
  }
done;
Run Code Online (Sandbox Code Playgroud)

运作方式如下:

wait -n(可能有许多)后台作业之一退出后立即退出。它始终求值为true,并且循环一直进行到:

  1. 退出代码127:上一个后台作业成功退出。在这种情况下,我们将忽略退出代码,并退出代码为0的子外壳。
  2. 任何后台作业均失败。我们只是使用该退出代码退出子外壳。

使用set -e,这将确保脚本将尽早终止并传递任何失败的后台作业的退出代码。