Home 和 End 键失效
命令行程序中一个常见的问题是 Home 和 End 等按键无法按预期工作。这通常是因为终端模拟器在按下这些键时会发送多字符的转义序列,而正在运行的程序(例如你的 shell)不知道如何正确解释它们。通常可以通过配置该程序,使其在接收到特定的转义序列时执行正确的操作来解决此问题。因此,解决方案因程序而异。
首先,你应该检查那些可能影响许多程序行为的常见原因。
TERM
按键失效的首要原因是将 TERM 环境变量覆盖为与你的 shell 冲突的值。所有现代终端都足够智能,能够设置自己的 TERM 变量,因此在深入研究程序配置之前,请确保你没有错误地覆盖它(例如在你的 ~/.bashrc 中)。再次强调,不要手动设置 TERM —— 让终端自动处理。
如果你不喜欢终端选择的 TERM 值(例如你想要 'xterm-256color' 但它选择了 'xterm'),通常有一种方法可以配置终端来正确覆盖它,而无需直接更改 TERM 变量。
对于 xterm 和 urxvt,可以在 X resources 中设置
~/.Xresources
XTerm*termName: xterm-256color URxvt*termName: rxvt-unicode
对于 GNU Screen,可以在 ~/.screenrc 中设置
~/.screenrc
term screen-256color
对于 Tmux,可以在 ~/.tmux.conf 中设置(参见 tmux#Configuration)
~/.tmux.conf
set -g default-terminal screen-256color
Shell 提示符
Home 和 End 键失效的另一个可能原因是格式错误的自定义 shell 提示符。Shell 会尝试计算 PS1 环境变量中所含提示符的实际长度,但如果 PS1 包含一些转义序列(例如用于彩色文本的序列),shell 可能会认为它们是长度非零的实际可打印字符。这显然会导致文本渲染错误。
为了避免这种情况,你应该将 PS1 中的不可打印内容包裹在 \[ 和 \] 之间,以便 shell 能够理解它们实际上是不可打印的。例如,你 .bashrc 中的这一行
PS1="\e[32m\u \e[34m\w \e[37m\$ \e[0m"
应该变为这样
PS1="\[\e[32m\]\u \[\e[34m\]\w \[\e[37m\]\$ \[\e[0m\]"
更多信息,请参考 Bash/提示符自定义。
Readline
许多命令行应用程序使用 Readline 库来读取输入。因此,正确配置 Readline 在许多情况下可以修复 Home 和 End 键。Readline 在 /etc/inputrc(全局映射)和 ~/.inputrc(用户映射)中维护了一些较冷门按键的映射。
在默认的 /etc/inputrc 中,有几行尝试处理常见的 Home/End 转义序列
"\e[1~": beginning-of-line "\e[4~": end-of-line "\e[7~": beginning-of-line "\e[8~": end-of-line "\eOH": beginning-of-line "\eOF": end-of-line "\e[H": beginning-of-line "\e[F": end-of-line
如果你的按键不起作用,可能是因为你的特定终端发送的转义序列不在这个列表中。首先你需要找出发送的是什么转义序列。要查看它们,你可以使用名为 "quoted-insert" 的 Readline 命令,或者运行 showkey --scancodes 命令,该命令会原样输出按键的值。quoted-insert 的默认绑定是 Ctrl+v。
例如,你可以在终端中输入以下序列
Ctrl+v首页空格键Ctrl+v结束
并得到输出
^[[1~ ^[[4~
^[ 表示 shell 中的转义字符,这意味着你的 Home 键转义序列为 [1~,End 键转义序列为 [4~。由于这些转义序列未列在默认的 Readline 配置中,你需要将它们添加进去
"\e[1~": beginning-of-line "\e[4~": end-of-line
注意 Readline 使用 \e 来表示转义字符。
Terminfo
对于不使用 Readline 的程序(例如 ncurses),你可以尝试编辑 terminfo 以更改某些操作发送到终端的转义序列。
首先将现有的 terminfo 保存到文件中
$ infocmp $TERM > terminfo.src
然后编辑它来更改转义序列。例如更改 khome 和 kend
khome=\E[1~, kend=\E[4~,
然后编译新的 terminfo(将其保存到你的 ~/.terminfo 目录中)
$ tic terminfo.src
最后,在 shell 的 环境变量 中指定新的 terminfo
export TERMINFO=~/.terminfo
其他应用程序
如果上述步骤无法解决问题,这可能是一个程序特定的问题而非系统全局问题。你可能需要查阅该程序的文档来了解如何修复。以下是常见程序的修复方法。
Lynx
你可以使用与 Readline 相同的 quoted-insert 字符来添加按键绑定,但使用 \033 来表示转义字符
lynx.cfg
setkey "\033[1~" HOME setkey "\033[4~" END
URxvt/Rxvt
使用与 Lynx 相同的转义序列格式,在你的 X resources 中添加转义序列绑定
URxvt.keysym.Home: \033[1~ URxvt.keysym.End: \033[4~ URxvt.keysym.KP_Home: \033[1~ URxvt.keysym.KP_End: \033[4~
其中 KP_Home 和 KP_End 是数字小键盘的 Home 和 End 键。这些绑定可能也会修复在 URxvt 中运行的程序,例如 nano。
另一种解决方案是在 /etc/inputrc 中添加以下部分
# those two are for rxvt "\e[7~":beginning-of-line "\e[8~":end-of-line
Zsh
使用 terminfo(5) 数据库来设置正确的按键绑定,参见 Zsh#Key bindings。
Less
lesskey 源文件
对于 less 582 及更高版本,可以使用位于 $XDG_CONFIG_HOME/lesskey 或 $HOME/.config/lesskey 或 $HOME/.lesskey 下的纯文本配置文件。
$HOME/.config/lesskey
#line-edit \e[1~ home \e[4~ end