开机自启的tmux

橘子 发布于 2025-08-15 97 次阅读


自启tmux

橘子冒出来一个奇怪的需求……

有一个脚本,我希望它能在开机时启动。但是我出于一些原因,希望能使用tmux启动它。

tmux

贴一个菜鸟教程的参考链接

tmux(Terminal Multiplexer)是一个终端复用工具,它允许你在单个终端窗口中创建多个虚拟终端会话,并能保持这些会话在后台运行。与直接使用终端相比,tmux 提供了更强大的会话管理功能。

常用命令如下:

# 新建一个session并且给它命名
tmux new -s <name>
# 列出所有会话
tmux ls
# 重新连接到指定会话
tmux attach -t <name>
# (在tmux会话中使用)分离出会话
tmux detach

此外,tmux提供了很多命令的快捷键。最常用的是分离会话。处于一个tmux会话中时,使用Ctrl+b d能分离当前会话。说的更详细一些就是:

  • 你开启了一个tmux会话,从你自己的终端(例如bash)切换到了tmux终端。
  • 你现在在一个tmux会话中,使用的是tmux的终端。
  • 按下Ctrl+b,现在tmux在等待你输入下一个指令,再按下b。
  • 然后你就会发现你退出了tmux会话,回到了原来的终端。tmux终端还在后台继续运行着。

定时任务

以前写过一篇文章,介绍如何使用crontab启动定时任务:使用crontab设置服务器定时任务 – 软软橘子

那么,我能不能定时让任务运行在tmux中呢……比起使用服务或者直接让它在后台运行,这样做的好处是:

  • 你可以随时回到这个会话查看它的状态。
  • 你可以提前配置好这个会话的环境,当需求改变时,在这个会话中停止原指令,运行新的指令。

使用cron运行tmux

当你尝试写一个脚本,其中只包含tmux new,然后运行这个脚本时,你会发现这个脚本给你打开了一个新的会话,而这个指令是阻塞的,脚本后续的命令被阻断了。例子如下:

#!/bin/bash
tmux new -s my-session
# 此时新建了一个tmux会话,后续的命令不会被执行
cd ~/task/
bash ./task.sh

所以,原本人类逻辑上的命令输入不能直接写给脚本。

现在逻辑应该转变为:

  1. 新建一个tmux会话,但是不进入。然而要实现这点,需要使用-d,他表示分离,也就是detach
  2. 向现有的会话输入指令。使用命令send,示例:tmux send -t my-session "echo hello world".

此外,tmux默认使用的终端可能不是bash,而是sh。所以,如果有需求,还需要做终端的切换和环境变量的载入。

所以,以启动一个python虚拟环境,并且运行脚本为例,脚本代码如下:

#!/bin/bash

. /etc/profile
. ~/.bash_profile

echo "sleeping 5 seconds..."
sleep 5
echo "wake up! running tmux..."

tmux new -s my-session -d

tmux send -t my-session "bash" ENTER
tmux send -t my-session "source $HOME/python_env/bin/activate" ENTER
tmux send -t my-session "cd $HOME/service"  ENTER
tmux send -t my-session "python3 ./main.py" ENTER

这里有几个要点。

  1. 开头的注释表示了需要使用哪个终端运行脚本,并且随后读入了配置文件。
  2. 有一段sleep指令。这是因为这段指令是为开机自启设计的,有可能环境未来得及配置,这里做一些等待。
  3. 在命令后加了一个ENTER,表示命令传入之后还要紧接着一个回车。
  4. 首先传入的命令是bash。这是因为,你仅仅告诉系统,用什么运行这个脚本还不够;你还要告诉被这个运行的tmux,tmux应该使用什么运行接下来传入的指令。比较绕,理解一下吧。
  5. 无法预期程序的目录,最好指定绝对路径。

然后使用crontab -e打开定时任务编辑器添加如下指令来开机自动运行。

@reboot /path/to/your/script.sh