在使用putty时,zsh中的Home/End键无法正常工作。

45
我在Ubuntu上的一台机器上使用zsh作为默认shell,并且在gnome-terminal上一切正常(据我所知,它模拟了xterm)。但是当我通过ssh和putty从Windows机器登录时(它们也模拟xterm),突然间home/end键不再起作用。
我已经通过将以下几行代码添加到我的zshrc文件中解决了这个问题...
bindkey '\e[1~' beginning-of-line
bindkey '\e[4~' end-of-line

...但我仍然想知道这里出了什么问题。有任何想法吗?

感谢以上的绑定。现在在SecureCRT中可以正常工作了。 - MikeRoger
感谢您的指令。对我来说,这个设置起作用了:bindkey '^[OH' beginning-of-linebindkey '^[OF' end-of-line - codeman48
8个回答

85

我发现这是一个组合结果:

第一点

ZSH的开发者不认为ZSH应该定义HomeEndDel等键的操作。

Debian和Ubuntu通过在全局/etc/zsh/zshrc文件中定义普通用户期望的常规操作来解决此问题。以下是相关代码(在Debian和Ubuntu上相同):

if [[ "$TERM" != emacs ]]; then
[[ -z "$terminfo[kdch1]" ]] || bindkey -M emacs "$terminfo[kdch1]" delete-char
[[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
[[ -z "$terminfo[kend]" ]] || bindkey -M emacs "$terminfo[kend]" end-of-line
[[ -z "$terminfo[kich1]" ]] || bindkey -M emacs "$terminfo[kich1]" overwrite-mode
[[ -z "$terminfo[kdch1]" ]] || bindkey -M vicmd "$terminfo[kdch1]" vi-delete-char
[[ -z "$terminfo[khome]" ]] || bindkey -M vicmd "$terminfo[khome]" vi-beginning-of-line
[[ -z "$terminfo[kend]" ]] || bindkey -M vicmd "$terminfo[kend]" vi-end-of-line
[[ -z "$terminfo[kich1]" ]] || bindkey -M vicmd "$terminfo[kich1]" overwrite-mode

[[ -z "$terminfo[cuu1]" ]] || bindkey -M viins "$terminfo[cuu1]" vi-up-line-or-history
[[ -z "$terminfo[cuf1]" ]] || bindkey -M viins "$terminfo[cuf1]" vi-forward-char
[[ -z "$terminfo[kcuu1]" ]] || bindkey -M viins "$terminfo[kcuu1]" vi-up-line-or-history
[[ -z "$terminfo[kcud1]" ]] || bindkey -M viins "$terminfo[kcud1]" vi-down-line-or-history
[[ -z "$terminfo[kcuf1]" ]] || bindkey -M viins "$terminfo[kcuf1]" vi-forward-char
[[ -z "$terminfo[kcub1]" ]] || bindkey -M viins "$terminfo[kcub1]" vi-backward-char

# ncurses fogyatekos
[[ "$terminfo[kcuu1]" == "^[O"* ]] && bindkey -M viins "${terminfo[kcuu1]/O/[}" vi-up-line-or-history
[[ "$terminfo[kcud1]" == "^[O"* ]] && bindkey -M viins "${terminfo[kcud1]/O/[}" vi-down-line-or-history
[[ "$terminfo[kcuf1]" == "^[O"* ]] && bindkey -M viins "${terminfo[kcuf1]/O/[}" vi-forward-char
[[ "$terminfo[kcub1]" == "^[O"* ]] && bindkey -M viins "${terminfo[kcub1]/O/[}" vi-backward-char
[[ "$terminfo[khome]" == "^[O"* ]] && bindkey -M viins "${terminfo[khome]/O/[}" beginning-of-line
[[ "$terminfo[kend]" == "^[O"* ]] && bindkey -M viins "${terminfo[kend]/O/[}" end-of-line
[[ "$terminfo[khome]" == "^[O"* ]] && bindkey -M emacs "${terminfo[khome]/O/[}" beginning-of-line
[[ "$terminfo[kend]" == "^[O"* ]] && bindkey -M emacs "${terminfo[kend]/O/[}" end-of-line
fi

如果你连接的是Debian或Ubuntu系统,那么你不需要做任何操作。一切都应该自动工作(如果没有,请参见下文)。

但是,如果你连接的是另一个系统(例如FreeBSD),可能没有用户友好的默认zshrc文件。解决方法当然是将Debian/Ubuntu zshrc文件中的内容添加到你自己的.zshrc文件中。

第二个问题

Putty将xterm作为终端类型发送到远程主机。但某些地方出了问题,没有发送正确的控制代码以获得人们从xterm终端期望的HomeEnd等功能。或者不希望xterm终端发送这些内容... (但在ZSH中配置后,Del键可以正常使用)。此外请注意,使用xterm终端时,您的数字小键盘在Vim中也会表现出奇怪的行为。

解决方法是配置Putty发送另一种终端类型。我尝试过xterm-colorlinux。使用xterm-color解决了Home/End问题,但数字小键盘仍然不正常。将其设置为linux可以解决这两个问题。

你可以在Putty中的连接->数据中设置终端类型。不要试图在你的.zshrc文件中使用export TERM=linux来设置终端类型,那是错误的。终端类型应该由你的终端应用程序指定。因此,例如,如果你从具有Mac SSH客户端的Mac主机连接,则它可以设置自己的终端类型。

请注意,TERM指定你的终端类型,与你连接的主机无关。我可以在Putty中将我的终端类型设置为linux并连接到FreeBSD服务器而没有任何问题。

因此,修复这两个问题,你应该就没问题了 :)


4
修复有趣的键盘行为的另一种方法:打开会话设置,进入“终端 -> 特性”并勾选标记为“禁用应用程序键盘模式”的框。请参见此处:http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter4.html#config-appkeypad - exhuma
1
我不得不在viins模式下添加“vi-beginning-of-line”和“vi-end-of-line”绑定,以完全解决我的zsh + putty问题。现在它可以正常工作了。 - Daniel Baulig
我没有成功使用@hopla粘贴的.zshrc代码。所以我不得不使用以下zsh维基页面[http://zshwiki.org/home/zle/bindkeys]上的解决方案,其中讲述了从$terminfo[]读取加上hopla设置终端类型为“linux”的解决方案。ZSH维基页面说要做基本相同的事情,但不要传递“-M…”选项给bindkey。然而,这只在“vi” bindkey模式下对我有效。 - Alex Q
@exhuma 的修复方法对我很有效。我在使用 PuTTy -> zsh -> tmux -> emacs 从 Windows 连接 CentOS5 时遇到了问题。 - BungleFeet
自2001年起,PuTTY的终端类型在Dickey Terminfo中为putty。https://invisible-island.net/ncurses/terminfo.ti.html#tic-putty - JdeBP

21
在PuTTY的配置对话框中,转到 Connection->Data 并在连接之前在终端类型字符串中键入 linux

就是那个! - lewis4u
这对我有效,但是如果我想在 Midnight Commander 中使用鼠标,我必须使用 mc -x 启动它。 - Melebius
在Win10中,我的PuTTY 0.73 64位版本中没有“连接-->数据”部分,只有“连接-->SSH”,而且我无法找到“终端类型”选项。也许这个答案已经过时了? - Eric
@Eric 不,对我来说在Win10的PuTTY 0.74 64位中,连接-->数据仍然存在。 - Alex thunder Shevchenko

9

距离这个问题首次发布已经将近11年了。当时,一些 distro 中确实提供了 putty 的 terminfo 条目,但是效果一般。多年以来,情况得到了改善,并且过去十年所需的 hack 已不再需要。PuTTY 仍然默认将 TERM 设置为 xterm 以确保兼容性,但如果你连接的是现代、最新的系统,你很可能会尝试覆盖此设置并将其设置为 putty-256color

  1. 确保主机具有putty-256color的终端信息条目:toe -a | grep -F putty
  2. 撤销曾经启用的任何黑科技,以使PuTTY与zsh或其他程序正常工作。
  3. 确保PuTTY已经更新至最新版本。它不会提示您更新,如果过时了,您可能会遇到许多相同的问题。您可以使用Chocolatey之类的工具自动更新它。
  4. 在PuTTY的配置对话框中,转到Connection->Data,将 "Terminal-type string" 设置为putty-256color
  5. 在同一个配置屏幕上,在添加一个新环境变量以启用24位颜色。虽然这个变量没有标准化,但它被许多其他主流终端仿真器(例如iTerm2)发送,并且许多程序都能理解它。
    1. 变量:COLORTERM
    2. 值:truecolor
  6. 截至编写本文时,我还没有找到默认接受SSH上的COLORTERM变量的发行版。您需要编辑主机上的OpenSSH配置以允许它。例如,在类似于Debian的发行版上,编辑/etc/ssh/sshd_config并将COLORTERM添加到AcceptEnv行。
  7. 现在一切都应该“正常工作”。如果不是:
    1. 确保在更改后重新连接,或者至少在更改TERM后运行exec zsh。zsh在运行时不会响应对TERM的更改。
    2. 确保TERM实际上设置为你想要的值:echo $TERM
    3. 您是否使用的是您发行版的最新版本?例如,即使您的版本仍然得到支持,如果您使用的是长期支持生命周期版本,则可能没有最新的终端信息条目。
    4. 您是否使用了screentmux?那是另一个大问题。首先测试排除问题所在。在tmux中尝试设置TERM=tmux-256color。在screen中尝试TERM=screen-256color
    5. 您是否使用PuTTY的最新版本?
    6. 您是否有实施键绑定或其他黑科技的RC文件?尝试使用默认的RC文件。
    7. 在尝试终端信息修复之前,是否已经更改了各种PuTTY设置以尝试解决问题?您可能需要重置这些设置。

这在我的 Gentoo 上运行良好 - 并且 Gentoo 在没有更改的情况下接受了 COLORTERM。Gentoo 还有一个用于 putty-256color 的屏幕终端信息,因此我希望屏幕也能正常工作。 - ZiggyTheHamster
我在 PuTTY 0.73 中没有连接 --> 数据。 - Eric

7

这对我很有效

bindkey -v

bindkey '\eOH'  beginning-of-line
bindkey '\eOF'  end-of-line

1
那弄乱了我的(有点)。现在,它不再是波浪号,而是将我的字母大写和小写化。 - Jon Lawton
对我来说,bindkey -v 就足够了。 - teadotjay
将以下内容放入我的.zshrc文件后:<c-p>和<c-n>不再起作用,只会打印出^P^N - 但使用'\e[1'和'\e[4'可以正常工作。 - MacMartin

6
适用于所有发行版(不一定适用于所有zsh版本,因此可能会有所不同)的适当答案是使用zkbd工具程序来创建键绑定。键盘定义中,由于键盘、工作站、终端、仿真器和窗口系统的大量组合,使得zsh无法为每种情况内置键绑定。在Misc/Functions中可以找到zkbd实用程序,可帮助您快速创建适合您配置的键绑定。将zkbd作为autoload函数或shell脚本运行。
zsh -f ~/zsh-4.3.17/Functions/Misc/zkbd

当您运行zkbd时,它首先会要求您输入终端类型;如果它提供的默认值是正确的,只需按回车键即可。然后,它会要求您按下多个不同的键来确定您的键盘和终端的特性;如果zkbd发现任何异常情况,例如发送^H或^?的删除键,则会发出警告。
由zkbd读取的按键会记录为名为key的关联数组的定义,写入在主目录或ZDOTDIR目录下的zkbd子目录中的文件中。文件名由TERM、VENDOR和OSTYPE参数组成,用连字符连接。
您可以使用source或.命令将此文件读入.zshrc或其他启动文件中,然后在bindkey命令中引用key参数,如下所示:
          source ${ZDOTDIR:-$HOME}/.zkbd/$TERM-$VENDOR-$OSTYPE
          [[ -n ${key[Left]} ]] && bindkey "${key[Left]}" backward-char
          [[ -n ${key[Right]} ]] && bindkey "${key[Right]}" forward-char
          # etc.

请注意,为了让 autoload zkbd 正常工作,zkbd 文件必须位于您的 fpath 数组中命名的某个目录中(请参阅 zshparam(1))。如果您使用的是标准 zsh 安装,则应该已经满足这一条件;如果不是,请将 Functions/Misc/zkbd 复制到适当的目录中。
请参阅 man -P "less -p 'keyboard definition'" zshcontrib,或搜索 meta-manpage zshall

3

看起来是一个Putty的问题。Gnome终端发送代码^[OH^[OF分别代表Home和End,而Putty发送^[[1~^[[4~。在Putty中有一个选项可以将Home/End键从标准模式更改为rxvt模式,这似乎修复了Home键,但未修复End键(现在发送^[Ow)。猜想现在是时候在某个地方提交错误报告了... :-)


1

这对我有用。

将这些行添加到~/.zshrc文件中

bindkey "\e[1;5D" backward-word
bindkey "\e[1;5C" forward-word

# ctrl-bs and ctrl-del
bindkey "\e[3;5~" kill-word
bindkey "\C-_"    backward-kill-word

# del, home and end
bindkey "\e[3~" delete-char
bindkey "\e[H"  beginning-of-line
bindkey "\e[F"  end-of-line

# alt-bs
bindkey "\e\d"  undo

0

这些绑定似乎并不是 Emacs 模式下默认绑定集的一部分。

在运行“bindkey -e”后,在我的默认 zsh 安装上执行“where-is beginning-of-line”仅显示它绑定到 ^a。也许你应该问问 zsh 开发者为什么会这样 :-)


默认的Ubuntu安装将它们绑定在全局zshrc文件中,但就我所知,这些绑定在Putty上不起作用。 - agnul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接