暂停bash脚本,直到完成先前的命令


20

我有一个bash脚本,如下所示:

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

我想在第一个循环之后创建另一个for循环,再继续执行30个循环。例如

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

我希望在开始新作业之前先完成第一组作业。但是由于这个原因,nohup它们似乎都是同时运行的。

我有,nohup因为我远程登录到服务器并在那里启动作业,然后关闭我的bash。有替代解决方案吗?


1
在手册中搜索wait内置文件。
聪桂

Answers:


22

您将需要使用wait命令为您执行此操作。您可以捕获所有子进程ID,然后专门等待它们,或者如果它们是脚本正在创建的唯一后台进程,则可以wait不带参数地调用。例如:

#!/bin/bash
# run two processes in the background and wait for them to finish

nohup sleep 3 &
nohup sleep 10 &

echo "This will wait until both are done"
date
wait
date
echo "Done"

6

几点:

  • 如果您的目标nohup是防止远程Shell退出杀死您的工作进程,则应nohup在脚本本身而不是在其创建的单个工作进程上使用。

  • 正如解释在这里nohup只是阻止过程从接收SIGHUP并从与终端交互,但它不破壳及其子进程之间的关系。

  • 由于上面的要点,无论有无nohupwait两个for循环之间的简单交互将导致for仅在第一个循环启动的所有子进程for都退出后才执行第二个循环。

  • 用一个简单的wait

    等待所有当前活动的子进程,返回状态为零。

  • 如果for仅在第一个没有错误的情况下才需要运行第二个,则需要使用来保存每个工作进程PID $!并将它们全部传递给wait

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }

服务器上可能正在运行其他作业。所以我只是想等我批..他们是如此他们下运行[R脚本Rcc1plustop命令
masfenix

我也想在其中使用nohup在“并行”中运行所有命令。基本上,这些是针对科学程序的模拟。我想总共运行180次仿真,但每批60次。计数器也需要从1增加到180。如果我一次进行一次,这将花费很长时间。
masfenix

wait导致bash等待它催生本身,没有别的后台作业。这里可能会有一些混乱-这些for循环,您是否将它们保存到文件中并作为脚本调用它们(由于##script行原因,我假设是这样),还是在终端中手动键入它们?
Matei David

-1

使用fg内置的。等待直到后台进程完成。

尝试help fg获取详细信息。


脚本在没有作业控制的情况下运行。
库沙兰丹

-1

如果在两个for循环之间插入类似以下代码段的内容,则可能会有所帮助。

flag=0

while [ flag -eq 0 ]
do
  ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null
  flag=${?}
  sleep 10
done

当然,如果您的应用程序Rscript有可能无法成功完成并徘徊,那么您的第二个for循环可能没有运行的机会。上面的代码段假定,带有标识符的所有过程Rscript --vanilla将正确完成并消失。在不知道您的应用程序做什么以及如何运行的情况下,我不得不依靠这个假设。

编辑

根据评论,这将更好地满足您的需求。(它包括您的原始代码以及完成检查逻辑)

for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
pids[$i]=${!}
done

flag=0

while [ flag -eq 0 ] 
do
  for PID in $(echo ${pids[@]})
  do
    flag=1
    ps -ef | grep ${PID} | grep -v grep >/dev/null; r=${?}
    if [ ${r} -eq 0 ]
    then 
      flag=0
    fi
  done
done

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

中的进程名称有时top显示Rcc1plus
masfenix

在这种情况下,您将需要找到一个公分母,并显示在ps -ef清单中。或在每个nohup命令之后,通过以下方式将PID记录到变量(最好是数组)中,echo ${!}并检查这组PID。当它们全部消失后,您可以进入第二个for循环
MelBurslan,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.