如何等待进程结束然后执行一系列操作(例如终止 tmux 会话)而不阻塞我的主终端?

如何等待进程结束然后执行一系列操作(例如终止 tmux 会话)而不阻塞我的主终端?

我正在尝试在 tmux 内部“重新实现”nohup(因此在不阻止我的情况下分派作业,然后终止充当 nohup 的 tmux 命令)。我的尝试就在这里(它有几个问题,正如开头所概述的那样,它不起作用,但是这是一个单独的问题,这个问题是关于脚本的最后一部分)。我现在的主要问题是,一旦后台运行的真实 python 脚本完成,我想终止 tmux 会话。这是我的完整尝试:

# - get a job id for this tmux session
export SLURM_JOBID=$(python -c "import random;print(random.randint(0, 1_000_000))")
echo SLURM_JOBID = $SLURM_JOBID
export OUT_FILE=$PWD/main.sh.o$SLURM_JOBID
export ERR_FILE=$PWD/main.sh.e$SLURM_JOBID

# - CAREFUL, if a job is already running it could do damage to it, rm reauth process, qian doesn't do it so skip it
# top -u brando9
# pkill -9 reauth -u brando9

# - start tmux, 
https://unix.stackexchange.com/questions/724877/custom-kerberos-tmux-doesnt-let-me-name-my-sessions-help-forcing-it
tmux new -s $SLURM_JOBID
# /afs/cs/software/bin/krbtmux new -s $SLURM_JOBID
# cat /afs/cs/software/bin/krbtmux

# - reauth
# /afs/cs/software/bin/reauth
echo $SU_PASSWORD | /afs/cs/software/bin/reauth
# echo 'Secret' | /afs/cs/software/bin/reauth
# echo 'totally secret password' | kinit [email protected]
# to see reauth running
# top -u brando9 

# - expt python script
python expts.py &
python -u ~/diversity-for-predictive-success-of-meta-learning/div_src/diversity_src/experiment_mains/main_sl_with_ddp.py --manual_loads_name sl_hdb1_5cnn_adam_cl_filter_size --filter_size 4 > $OUT_FILE 2> $ERR_FILE &
export JOB_PID=$!
echo JOB_PID = $JOB_PID

# - Echo tmux id, should be jobid
tmux display-message -p '#S'
echo SLURM_JOBID = $SLURM_JOBID

# - detach current tmux session
tmux detach &

# - wait for pid from python to be done, if done kill this tmux sess
wait $JOB_PID
tmux ls
tmux kill-session -t $SLURM_JOBID
# check it was killed
tmux ls

# - Done
echo "Done with bash script (experiment or dispatched daemon experiments). "

但上面的方法不起作用,因为:一旦 python 脚本运行并被调度&,我想要的是在该工作完成后终止 tmux 会话。我最后尝试了,但我怀疑它不会起作用。我认为它不起作用,因为一旦它运行,tmux detach &它将退出 tmux 会话并wait ...在 tmux 之外运行命令并阻止我的主终端。相反,我想要的是在 tmux 内部运行 wait 命令(为了不阻止我),一旦 python 脚本完成,就完全终止 tmux 会话。但这只是为我的脚本的最后部分添加上下文。

我该如何使其正常工作?

有关的:在 Linux 中如何使用需要密码的命令进行身份验证?

答案1

您可以使用;运算符来链接命令,并使用&运算符将​​它们发送到后台。将命令括在括号中,将整个组发送到后台。这是一个演示:

tmux new -s test
(sleep 15 ; tmux kill-session -t test) &
tmux detach

while true ; do 
  if ! tmux ls 2> /dev/null | grep 'test:' ; then
    echo tmux test disconnected
    break
  fi
  sleep 1 # limit polling rate
done

答案2

您不能wait以这种特殊方式使用,因为wait需要进程之间的父子关系。使用;也不起作用,因为这只是一个命令分隔符,即命令必须完成,直到提示符返回给您。

相反,我相信您正在寻找的只是类似于以下示例的内容:

### Random SLURM_JOBID value
export SLURM_JOBID=$(python3 -c "import random;print(random.randint(0, 1_000_000))")

### Init tmux session
tmux new -s "$SLURM_JOBID"
### --- tmux session ---
### Test command: runs in the background of a detached tmux session 
### and once finished will self-destruct that same detached tmux session

(for  i in $(seq 1 30); do sleep 1 ; done && tmux kill-session -t "$SLURM_JOBID" ) & tmux detach

执行上述命令后,您将立即返回到源自 tmux 的 shell。

执行 - 在循环的 30 秒运行时间内 - 以下命令将确认您tmux确实仍然存在于后台(您甚至仍然可以使用 重新附加到它tmux attach

> ps aux | grep tmux
user       12579  0.0  0.0   5880  3928 ?        Ss   10:26   0:00 tmux
user       12613  0.0  0.0   3876  1836 pts/0    S+   10:27   0:00 grep --color=auto tmux

> tmux list-sessions
683635: 1 windows (created Wed Nov 30 10:26:02 2022)

30 秒后执行相同的命令将确认其父tmux会话不再存在。

> ps aux | grep tmux
user       12706  0.0  0.0   3876  1836 pts/0    S+   10:30   0:00 grep --color=auto tmux

> tmux list-sessions
no server running on /tmp/tmux-0/default



命令语法解释
(for  i in $(seq 1 30); do sleep 1 ; done && tmux kill-session ) & tmux detach

上述命令有几个独特的方面,我将尝试一一讨论它们:

  • 第1部分: [CMD1] && [CMD2]

在上述命令的上下文中,[CMD1]对应[CMD2]于以下内容:

[CMD1] =for i in $(seq 1 30); do sleep 1 ; done

[CMD2] =tmux kill-session -t "$SLURM_JOBID"

在两个不同的命令之间使用双与号,即[CMD1] && [CMD2]强制 shell 等待并执行[CMD2]if AND 仅当[CMD1]成功完成时。

换句话说,在我们的命令上下文中,shell 被告知开始循环,运行 30 次迭代sleep 1,一旦循环完成,才执行tmux kill-session

您可以通过在会话内部执行tmux以下命令组合来自行测试此行为:

for  i in $(seq 1 10); do sleep 1 ; done && tmux kill-session 

循环将启动,并在前台运行,并保留您的提示。

如果你让它运行 10 秒并完成,它将执行tmux kill-session后面的部分&&,并销毁它自己的tmux会话,让你返回到之前的 shell。

另一方面,如果您发送CTRL+z并在执行中终止循环,您的tmux会话将继续存活一天,因为 shell 会将我们的 SIGINT 注册为不成功[CMD1],并且不允许执行[CMD2]右侧的SIGINT。&&


  • 第2部分: ( [CMD1] && [CMD2] )

多个命令周围的括号允许对它们进行分组和隔离,从而产生类似于数学运算顺序的行为。


  • 第 3 部分: ( [CMD1] && [CMD2] ) &

在括号后添加“&”&使我们能够在后台执行括号内的全部内容。

如果不使用(...)在后台执行多个命令,就会变得更加乏味和复杂,因为例如不能简单地使用[CMD1] & && [CMD2][CMD1] && & [CMD2]

另一方面,使用(...)它甚至可以执行如下复杂的操作:

((for  i in $(seq 1 5); do sleep 1 ; done && echo "first loop finished" )  && ( for i in $(seq 1 5); do sleep 1; done && echo "second loop finished" ) && sleep 5 && tmux kill-session ) &

它将执行第一个循环,一旦完成,将报告其状态,然后将开始第二个循环,一旦完成,其状态也将被报告,然后将有 5 秒的sleep延迟,然后会话将自行破坏。

  • 第 4 部分: ([CMD1] && [CMD2]) & tmux detach

最后一项添加是tmux detach允许我们返回到发起tmux会话的 shell。值得一提的是,通过在两个单独的行上运行以下两个命令也可以获得相同的行为:

(for  i in $(seq 1 30); do sleep 1 ; done && tmux kill-session -t "$SLURM_JOBID" ) &
tmux detach

一首接着一首,因为单曲&属于我们单行的左侧。

相关内容