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

mas*_*nix 34 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
Run Code Online (Sandbox Code Playgroud)

我想在第一个循环之后创建另一个 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
Run Code Online (Sandbox Code Playgroud)

我希望在开始新工作组之前完成第一组工作。但是因为nohup它们似乎都是同时运行的。

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

小智 40

您将需要使用该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"
Run Code Online (Sandbox Code Playgroud)


Mat*_*vid 14

几点:

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

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

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

  • 用一个简单的wait

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

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

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }
    
    Run Code Online (Sandbox Code Playgroud)


Mel*_*lan 0

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

flag=0

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

当然,如果您的应用程序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
Run Code Online (Sandbox Code Playgroud)