如何让 Ctrl+D 分离 tmux,同时保留 Bash 中的 GNU readline 功能?

如何让 Ctrl+D 分离 tmux,同时保留 Bash 中的 GNU readline 功能?

根据我对此日复一日的研究,我可能在寻求不可能的事情。

情况

  • 我已经.bashrc很好地配置好了,可以tmux在连接时产生一个新的,或者如果存在的话,附加到它。

  • 总是Ctrl+D退出 shell 会话。它已经刻在我的肌肉记忆中。在做了三十年系统管理之后忘记它也是不可能的事情。

  • 能够摆脱tmux仅使用Ctrl+ 的束缚D,而不是让它杀死我的外壳。


我不完美的方法

绑定Ctrl+D到。detach.tmux.conf

问题是,我emacs的肌肉记忆中也刻有按键绑定,因此当我开始编辑命令行时,我会按Ctrl+D来使用 GNU readline“删除光标下的字符”。相反,绑定tmux会吞掉Ctrl+ D,因此我会立即分离。如果我在 中编辑,情况也是如此emacs


另一种有缺陷的方法

GNU readline 将在空行上获取 EOF,然后退出 shell。因此,我尝试改为使用 exit .bashrc

trap "~/tmuxexit" EXIT

内容为tmuxexit

tmux detach-client -s main

最初这似乎有效,因为在空行上按Ctrl+会报告:D

[detached (from session main)]

tmux ls有報告no server running on […]


我是否在追求不可能的事情?

答案1

我不确定我是否想出了最简单的解决方案。这个:

stty eof '^T'
bind '"\C-d": "\C-x\C-t\C-x\C-d"'
bind -x '"\C-x\C-t": _tmux_detach'
_tmux_detach() { [ -z "$READLINE_LINE" ] && tmux detach-client; }
bind '"\C-x\C-d": delete-char'

解释:

  1. stty eof '^T'使您的终端不再在Ctrl+处发送 EOF D。现在是Ctrl+ T。新的组合键将像 readline 中的旧组合键一样运行,我的意思是只有当行是空时它才会退出 shell。我故意选择了Ctrl+ ,T因为您不太可能希望在空行中使用其默认绑定(转置字符)。

    我认为完全禁用 EOF ( stty eof undef) 会起作用,但事实证明 readline(?) 仍然会对之前定义的组合(如Ctrl+ D)做出反应,并且如果该行为空,则使 shell 注册 EOF。

  2. bind '"\C-d": "\C-x\C-t\C-x\C-d"'使Ctrl+ D“发送” Ctrl+ X, Ctrl+TCtrl+ X, Ctrl+ D。我们将分别利用这两个子序列。

  3. bind -x '"\C-x\C-t": _tmux_detach'– 从现在开始Ctrl+ XCtrl+T执行_tmux_detach

  4. tmux…这是一个在行 ( ) 为空时分离的函数$READLINE_LINE

  5. bind '"\C-x\C-d": delete-char'– 从现在开始Ctrl+ XCtrl+D删除指向的字符,就像Ctrl+D通常做的那样。


因此Ctrl+D将像这样工作:

  • 如果该行不为空,则该函数为无操作并delete-char执行其工作;
  • 如果该行为空,则函数执行其工作并且delete-char为无操作(它被触发但无任何操作)。

笔记:

  • READLINE_LINE是在 Bash 4.0 中引入的。
  • 如果您将代码粘贴到您的中,您可能需要改进它:在更改+的行为之前~/.bashrc检查 shell 是否在里面,这样外面的 shell就不会受到影响。tmuxCtrlDtmux
  • _tmux_detach在 之前执行非常重要delete-char。如果你颠倒顺序,那么你将引入一个错误:删除一个单独字符的Ctrl+D也会分离tmux

答案2

Kamil Maciorowski 的答案表明这是可能的,我感谢他。根据他提到的测试是否在 tmux 中来确定 ctrl-d 行为,以下内容似乎按预期工作,所以我正在扩展他的回答。

.bashrc 中的测试:

  • 如果不在 tmux 会话中,则不要重新映射键
  • 如果存在 tmux 会话,则附加到该会话,并保留重新映射的键
  • 如果没有,则使用新密钥创建一个新会话
if [[ "$TERM" != "screen-256color" ]];then
    if tmux has-session -t main 2>/dev/null; then
        tmux attach -t main
    else
        tmux new -s main
    fi
else
    stty eof '^T'
    bind '"\C-d": "\C-x\C-t\C-x\C-d"'
    bind -x '"\C-x\C-t": _tmux_detach'
    _tmux_detach() { [ -z "$READLINE_LINE" ] && tmux detach-client; }
    bind '"\C-x\C-d": delete-char'
fi

请注意“screen-256color”的使用(通过set -g default-terminal "screen-256color"在 .tmux.conf 中添加设置)。如果您不想使用扩展颜色图,您可以简单地在 .bashrc 代码片段中声明“screen”。

以上内容可能比需要的更符合我的偏好 - 这肯定不是进行这些测试的唯一方法,但对我来说有效。(更新为更智能的构造)

答案3

Zsh 版本..

# tmux detach or delete
function _delete_or_detach() {
    if [[ -n "${BUFFER}" ]]
    then
        zle delete-char-or-list
    else
        tmux detach-client
    fi
}
if [[ -n "$TMUX" ]]
then
  setopt ignoreeof
  zle -N _delete_or_detach
  bindkey "^D" _delete_or_detach
fi

相关内容