我已经设置了多个别名来 ssh 到不同的服务器
alias sa="ssh user1@server1"
alias sb="ssh user2@server2"
alias sc="ssh user3@server3"
当我从 tmux 运行这些命令时,所有窗口都重命名为ssh
,而不是sa
,sb
,sc
。如何让别名显示为窗口名称而不是实际进程名称?
编辑:使用 macOS 12.2.1、tmux 3.2a、zsh 5.8
答案1
初步说明
- 部分分析(如下)主要适用于 Linux。
- 该解决方案已在 Kubuntu 21.10 中测试并发布。直到那时,OP 才透露他们使用的是 macOS;结果发现该解决方案在 macOS 上不起作用。
- 我决定(暂时)不删除答案,但请注意,它在非 Linux 操作系统上可能会或可能不会起作用。
总结
alias sa='bash -c '\''exec -a "$0" ssh user1@server1 "$@"'\'' sa'
或者更好的(?)(unalias sa
如果需要的话,首先):
sa() {
bash -c 'exec -a "$0" ssh user1@server1 "$@"' sa "$@"
}
分析——你可以做什么tmux
tmux
默认情况下,根据活动窗格中正在运行的可执行文件更改窗口的名称。这由automatic-rename
选项:
automatic-rename [on | off]
控制自动窗口重命名。启用此设置后,tmux
将使用 指定的格式自动重命名窗口。如果在创建时使用或指定名称,或者稍后使用或使用终端转义序列automatic-rename-format
指定名称,则会自动为单个窗口禁用此标志。[…]new-window
new-session
rename-window
我假设您希望此设置保持启用状态。
您可以根据需要重命名窗口 ( ),并在调用 之前或之后tmux rename-window sa
重新启用设置 ( ) 。但是:tmux set-option -w automatic-rename on
ssh
- 如果在 之前
ssh
,则选择同一窗口中的另一个窗格将使其automatic-rename
完成其工作(您可能预料到这一点),但选择带有 的窗格ssh
会将窗口重命名为ssh
,而不是sa
; - 如果在之后
ssh
,则选择同一窗口中的另一个窗格(ssh
完成之前)将不会重命名该窗口。
可能还有其他缺点;这两种方法都不完美。还请注意,如果您set-option -w automatic-rename
在多个窗格中使用,则一个窗格中的命令可能会tmux
以不同于另一个窗格试图强加的方式配置窗口。来回更改设置并不是一个好的解决方案。
一个好的解决方案是自动将tmux
设置sa
为标题。我们需要一种方法来告诉tmux
使用字符串sa
而不是ssh
。为此,我们需要了解如何tmux
知道ssh
您正在运行。
分析——tmux
知道什么
tmux
为您的 shell 提供终端。当 shell 生成时ssh
,shell 通过将进程组设置为ssh
前台进程组,将自身置于后台。当ssh
退出时,作为父进程的 shell 会做出反应,通过将其进程组设置为前台进程组,将自身置于前台。这种“玩弄”的主要目的是使作业控制工作(后台进程的标准输入仍然连接到终端,以防万一fg
;但无法“窃取”输入,直到它们的进程组成为前台进程组)。
进程 (或其他进程) 能够tmux
知道前台可执行文件的名称,这只是此机制的一个有用的副作用。了解它提供的终端的前台进程组,tmux
可以找到作为组长进程的进程并自动调整标题。
shell 不会直接告知tmux
正在执行什么命令。如果是这种情况,一个足够聪明的 shell 可以传递sa
而不是ssh
。您的 shell 决定哪个进程组(以及何时)成为与终端(tmux
上下文中:窗格)关联的前台进程组。通过监视这一点,tmux
可以在窗格中找到前台进程。
别名不是进程。每个别名都运行一个名为 的可执行文件ssh
。tmux
无法知道您使用的别名。这就是为什么您的窗口被重命名为ssh
,无论您使用哪个别名。
解决方案
事实证明,前台可执行文件的名称对 来说并不重要tmux
。重要的是 中第一个(有人会说是“第零个”)以空字符结尾的条目/proc/PID/cmdline
。通常(按照惯例)它是可执行文件的路径或其名称;但实际上它可以是任何东西。
有多种方法可以运行ssh
(或其他方式)并指定自定义字符串。请参阅设置线程/proc/PID/cmdline
。在 Bash 中exec -a …
可以做到这一点。但不要直接从交互式 shell 调用它,exec
因为代替shell 中的内容与您想要运行的内容相同。因此您需要一个额外的内容bash
来替换它。例如:
bash -c 'exec -a "foo" sleep 300'
在 shell 内部调用上述命令tmux
将把tmux
窗口重命名为foo
(如果automatic-rename
是on
;则可能需要等待几秒钟)。
使用此方法的基本别名是:
alias sa='bash -c "exec -a sa ssh user1@server1"'
我注意到您的别名与附加参数配合得很好。我的意思是,例如,您的sa sleep 30
别名扩展为在服务器上ssh user1@server1 sleep 30
运行的合理命令sleep 30
。我们的别名尚不支持这一点。这是修复方法:
alias sa='bash -c '\''exec -a sa ssh user1@server1 "$@"'\'' whatever'
就像whatever
第二sh
个中的第二个 sh 是什么sh -c 'some shell code' sh
?我个人更喜欢传递所需的名称,而不是whatever
:
alias sa='bash -c '\''exec -a sa ssh user1@server1 "$@"'\'' sa'
或者也许(见干燥):
alias sa='bash -c '\''exec -a "$0" ssh user1@server1 "$@"'\'' sa'
注意sa
结尾处不需要匹配别名的名称。这里匹配是因为你想要这个。
别名有点复杂。不过,它还是有用的这超出了别名的用途。等效函数可能被认为更优雅。这是函数(unalias sa
如果需要,则首先执行):
sa() {
bash -c 'exec -a "$0" ssh user1@server1 "$@"' sa "$@"
}
笔记
exec -a
不可移植,它在 Bash 中有效,但在纯 中无效sh
。别名本身(或函数本身)在任何类似 POSIX 的 shell 中仍然有效。bash
无论您的主 shell 是什么,它都会显式调用。- 有其他工具可以读取
/proc/PID/cmdline
或等效信息。我们的解决方案可能会误导他们或使用它们的用户。例如,将在列中ps -eo pid,comm,command
打印,但在列中。ssh
comm
sa
command