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

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

我有一个 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 循环之后创建另一个 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命令来为您执行此操作。您可以捕获所有子进程 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"

答案2

几点:

  • 如果您的目标nohup是防止远程 shell 退出杀死您的工作进程,那么您应该nohup在脚本本身上使用,而不是在它创建的各个工作进程上使用。

  • 正如所解释的这里nohup仅阻止进程接收 SIGHUP 并与终端交互,但不会破坏 shell 与其子进程之间的关系。

  • 由于上述观点,无论有或没有,两个循环之间的nohup简单操作将导致仅在第一个循环启动的所有子进程退出后才执行第二个循环。waitforforfor

  • 用一个简单的wait

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

  • for如果仅当第一个中没有错误时才需要运行第二个,那么您需要使用 保存每个工作进程 PID $!,并将它们全部传递给wait

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

答案3

如果您在两个循环之间插入类似以下代码段的内容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

相关内容