我正在尝试在 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 会话。但这只是为我的脚本的最后部分添加上下文。
我该如何使其正常工作?
答案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
一首接着一首,因为单曲&
属于我们单行的左侧。