我的设置:在本地使用 Tmux,在不同的窗格中与不同的服务器建立许多连接
我想做的事:按下一个窗格内的快捷方式,即可打开一个已设置相同连接的新窗格。
为什么:工作流程。很多时候,当我在服务器上工作时,我需要打开一个新窗格来执行某些操作,同时其他一些操作正在运行。如果我可以打开一个已设置好所有内容的新窗格,我将节省大量的时间和精力。
我愿意通过其他方式来实现我想要做的事情。我可以在远程机器上设置 tmux,但我更喜欢在本地运行 tmux。
编辑:
我已经学会了 ssh 多路复用,这解决了我的问题的一部分(每个服务器只需登录一次)。我已将其添加到我的~/.ssh/config
文件中:
### Multiplexing ###
Host *
ControlMaster auto
ControlPath ~/.ssh/sessions/%C
ControlPersist 1h
现在我必须弄清楚如何在 tmux 中设置快捷方式以在新窗格中连接到同一主机。
答案1
解决方案
将以下脚本保存到_tmux_duplicate_pane
您的目录中PATH
:
#!/bin/bash
set -e
pid="$(tmux display-message -p '#{pane_pid}')"
pid="$(ps -o tpgid:1= -p "$pid")"
dir="$(readlink -f "/proc/$pid/cwd")"
cd -- "${dir:?}"
exe="$(readlink -f "/proc/$pid/exe")"
readarray -d '' args <"/proc/$pid/cmdline"
name="${args[0]}"
args=("${args[@]:1}")
tmux split-window "$@" -c "$dir" bash -c "exec -a ${name@Q} ${exe@Q} ${args[*]@Q}"
使脚本可执行(chmod +x _tmux_duplicate_pane
)。最后将其绑定到 中的按键tmux
。示例:
tmux bind-key -T prefix u run-shell _tmux_duplicate_pane
该命令旨在在 shell 中调用。在~/.tmux.conf
(永久设置)中,该命令应为bind-key …
。
现在prefixu应该可以按您想要的方式工作了。
解释
该脚本的工作方式是查找 中与当前窗格关联的进程的控制终端的前台进程组 ID tmux
。它假设前台进程组 ID 的领导者是您要复制的命令。它从中检索信息/proc
并tmux split-window
相应地调用。
注意事项
不要
_tmux_duplicate_pane
在窗格中作为命令运行。如果这样做,脚本将重复本身在新窗格中,它将变成以线性方式产生的叉炸弹。按照图示绑定到一个键并以这种方式使用它。该脚本假定您要执行的命令是活动窗格中前台进程组的领导者。如果出现以下情况,它将无法按预期工作:
- 窗格中的(本地)shell 不会在单独的进程组中运行命令(例如,shell 是禁用作业控制的 Bash);
- 或者您要执行的命令在管道中;例如,交互式 Bash(启用了作业控制)在一个进程组中运行整个管道,并且领导者是该行中的第一个命令;我们的脚本尝试复制领导者,但在管道的情况下,领导者可能不再存在,它可能提前退出;复制全部的管道是一项不简单的任务,依赖于 shell,脚本甚至不会尝试;
- 或者由于其他原因,您所追求的命令不是前台进程组的领导者。
该脚本应该能够成功复制在当前窗格中交互式现代 shell(如 Bash 或 Zsh)中运行的简单命令。
中的条目
/proc/$pid/cmdline
不足以复制命令。第 0 个条目是任意的(例如,参见help exec
Bash,注释-a
)。另一方面/proc/$pid/exe
,剩余的参数/proc/$pid/cmdline
也不足以复制命令,同一个可执行文件可能会根据第 0 个参数而有不同的行为。该脚本使用exec -a
Bash 并构建一个保留可执行文件和第 0 个参数的 shell 命令。在某些情况下
/proc/$pid/cmdline
,/proc/$pid/exe
可能不适合我们的目的。示例场景:- 复制过程可能已经改变了
cmdline
. 原始参数数组可能会丢失。 - 您调用并希望复制的进程可能已
exec
添加到具有另一个参数数组的另一个可执行文件中。您可能能够复制后者,但如果需要前者来为后者进行设置,则复制实例可能会失败。
但在这种情况下,这种情况不应该发生
ssh
。- 复制过程可能已经改变了
脚本将尝试复制任何命令,不仅仅是
ssh
。您可以添加一些逻辑、测试$exe
和/或${args[0]}
,使脚本成为无操作,除非命令是ssh …
。当重复命令退出时,其窗格中将没有 shell。除非选项
remain-on-exit
处于on
中,否则窗格将终止tmux
。一个简单的解决方法是强制交互式 shell后命令。例如,而不是tmux split-window … "…"
你做的tmux split-window … "…; bash"
。在复制命令时,脚本会尝试在原始进程的当前工作目录中执行此操作。在某些情况下,这将是错误的,特别是当进程将相对路径作为参数然后更改其工作目录时。脚本无法知道在调用命令时哪个目录是当前目录;它知道现在的当前目录可能相同也可能不同。
该脚本不会尝试复制原始进程的整个环境。如果您
SSH_ASKPASS=… ssh …
在窗格中运行并尝试复制此环境,则新ssh
命令将不知道该变量。/proc/$pid/environment
我猜可以进行解析;但脚本不会这样做。脚本在不同时刻检索不同的信息。这意味着它容易出现竞争条件。
脚本中的目的
cd
是当出现问题时让脚本尽早失败。您提供给脚本本身的参数将传递给
tmux split-window
。这意味着您可以绑定tmux bind-key … '_tmux_duplicate_pane -h'
并享受水平分割。