首页 > 解决方案 > 如何防止在新的登录 shell 中嵌套 tmux 会话?

问题描述

几乎所有在 shell 启动时设置 tmux 运行的解决方案(1、2 都依赖于一些环境变量,例如等。但是当我们启动一个登录 shell 时,例如 by ,所有变量都被清除,除了. 所以我们可以依靠来避免启动嵌套会话。假设默认设置是,我们设置以识别我们处于 TMUX 会话中。这适用于本地登录。$TMUX$TERMsu -$TERM$TERM$TERMxtermscreen.tmux.conf

现在,两台机器 A 和 B 使用相同的规则来控制嵌套会话,我们在机器 A 上的 tmux 会话中。当我们ssh从 A 远程登录(通过)到 B 时,tmux 会话不会在 B 上启动,因为$TERM已经设置为screen.

那么,有没有办法在不依赖环境变量的情况下找出我们已经在 tmux 会话中?

PS:

我发布了一个解决方法作为我用来实现上述行为的答案。但是更准确和更好的方法,例如可以使用 tmux 命令工作的方法,将不胜感激。

标签: sshloginenvironment-variablestmuxsu

解决方案


该解决方案的工作原理是确定当前终端是否连接到在同一台机器上运行的 tmux 服务器。为了找出连接,我们将使用伪终端对和I/O 统计破解。
但是,如果/procfs 或/dev文件不能被用户读取/写入,它可能会失败。例如,如果 tmux 服务器是由 root 用户启动的,非 root 用户将无法找到它。
此外,如果 tmux 服务器在我们尝试向其写入零的同时从其他来源接收数据,我们可能会得到误报。

将其放在.bashrc您想要的其他 shell 启动文件的末尾:

# ~/.bashrc

# don't waste time if $TMUX environemnt variable is set
[ -z $TMUX ] || return

# don't start a tmux session if current shell is not connected to a terminal
pts=$(tty) || return

# find out processes connected to master pseudoterminal
for ptm in $(fuser /dev/ptmx 2>/dev/null)
do
    # ignore process if it's not a tmux server
    grep -q tmux /proc/$ptm/comm || continue
    # number of bytes already read by tmux server
    rchar_old=$(awk '/rchar/ {print $2}' /proc/$ptm/io)
    # write out 1000 bytes to current slave pseudoterminal terminal
    dd bs=1 count=1000 if=/dev/zero of=$pts &>/dev/null
    # read number of bytes again and find difference
    diff=$(( $(awk '/rchar/ {print $2}' /proc/$ptm/io) - rchar_old ))
    # if it equals 1000, current terminal is connected to tmux server
    # however diff comes greater than 1000 most of the times
    [ $diff -ge 1000 ] && return
done

# start or attach to a tmux session
echo 'Press any key to interrupt tmux session.'
read -st1 key && return

# connect to a detached session if exists for current user
session=($(tmux list-sessions 2>/dev/null | sed -n '/(attached)/!s/:.*r//p'))
[ -z $session ] || exec tmux a -t ${session[0]}

# start a new session after all
exec tmux

推荐阅读