6. 您应该在您的系统上做什么

再次注意,困扰人们尝试修复其系统的主要问题是,他们通常在错误的地方进行修复。由于正常工作的部分通常只是偶然地工作,因此假设某些东西已损坏而尝试修复系统通常会导致将正确的设置更改为不正确的设置。

6.1. 需要做什么

6.1.1. 检测偏差

获得清晰解决方案的第一步是准确了解哪些终端有偏差,哪些没有。通常,它们都表现得像控制台一样,在这种情况下,使一切正常工作的修改是最小的。但是,如果您有一些有偏差的终端(例如,gnome-terminal 的有偏差版本),您将不得不以特殊的方式对待它。

以下 C 单行代码
void main(void) {int c; while(c = getchar()) printf("%d 0x%02X\n", c, c);}
可能会对您有所帮助。将该行放入名为ascii.c,使用 gcc ascii.c -o ascii 编译它,输入 ./ascii 并按下一个键,然后按 RETURN 键。该程序将显示生成的 ASCII 序列的十进制和十六进制代码(您可能需要先执行 stty erase ^- 以真正获取所有代码)。现在您可以轻松地看到 Backspace 键的作用:如果它发出 DEL (127),则您拥有一个标准模拟器;如果它发出 BS (8),则您拥有一个有偏差的模拟器。

6.1.2. 区分模拟器

如果您有一些有偏差的终端模拟器,则必须将其与标准模拟器区分开来。从理论上讲,这不应该是一个问题,因为终端数据库中对于具有不同序列的终端有不同的条目(使用的条目取决于TERM变量的值)。

在这里,我们采用的方法是gnome条目应该用于所有有偏差的 VT100 模拟器,而xterm条目用于标准模拟器。这与几个发行版一致(少数情况除外,例如 RedHat ≤5.0,其中xterm条目是有偏差的)。

但是,gnome-terminal 默认使用与 xterm 相同的条目,因此如果一个有偏差而另一个没有,则您需要找到一种方法来区分它们。选项termnamegnome-terminal 允许用户设置TERM变量为一个更合理的名称。但是,在旧版本的 gnome-terminal 中,此选项不起作用。而且,有时不容易修改 gnome-terminal 的启动方式。

这里的一个好主意是利用 gnome-terminal 设置了COLORTERM变量为gnome-terminal。因此,通过向 shell 配置文件添加一个简单的测试,我们可以修复TERM变量。

6.1.3. 修复终端数据库

我们现在的问题是终端数据库可能缺少一个gnome用于有偏差终端的条目(这发生在许多 termcapterminfo 版本上)。最近的 terminfo 数据库有一个条目gnome,但是,在任何情况下,由于 gnome-terminal 的行为基本上类似于 xterm 模我们著名的两个键,因此可以自动生成一个全新的正确条目。

6.1.4. 修复 Shell 行为

bash 和许多其他程序用于读取输入行的 readline 库可以自定义,以便识别特定的字符序列。自定义还可以取决于TERM变量,因此一旦我们可以区分终端,我们就可以对键盘进行微调。

此外,如果您希望 less 和其他执行原始行输入的应用程序正常工作,则必须使 shell 确信,在有偏差的终端模拟器下,擦除字符是 BS,而不是 DEL (在另一种情况下,Backspace 键已经发出 DEL,因此我们不必做任何事情)。这可以使用 stty 命令完成。

6.2. 如何做到这一点

Caution

这些修复程序有一些缺点。首先,它们仅适用于指定的终端。其次,理论上(但这不太可能发生)它们可能会混淆其他终端上的 readline 库。然而,这两个限制基本上是无害的。

首先,使用 infocmp gnome 检查您是否已经有一个gnome条目在您的 terminfo 数据库中(我们稍后将修复 termcap)。如果该条目不存在,则以下命令
bash$ tic <(infocmp xterm |\
        sed 's/xterm|/gnome|/' |\
        sed 's/kbs=\\177,/kbs=^H,/' |\
        sed 's/kdch1=\\E\[3~,/kdch1=\\177,/')
将在~/.terminfo中创建一个正确的条目。如果 root 用户启动相同的命令,它将在全局数据库中生成该条目(您可以通过设置TERMINFO~/.terminfo来覆盖此行为)。请注意,如果您的xterm条目已经有偏差(例如,您有 Red Hat ≤5.0),则脚本将复制它而不更改,这正是我们想要的。

现在,将以下代码片段添加到~/.inputrc[1]:
"\e[3~": delete-char
此行教导 readline 库如何管理标准模拟器的标准 Delete 键,并且如果运气好,它不应干扰其他终端。但是,现在我们还必须向库解释有偏差的终端上 DEL 字符的含义,例如通过添加
$if term=gnome
DEL: delete-char
Meta-DEL: kill-word
"\M-\C-?": kill-word
$endif
~/.inputrc。如果 xterm 也有偏差,则必须为其添加另外三行。另一方面,如果没有终端模拟器有偏差,则不需要此部分。所有这些更改都可以通过更改/etc/inputrc文件来全局完成。

请注意,条件赋值使有偏差的终端模拟器能够工作,前提是 TERM 变量设置正确。为了保证这一点,有许多技术。首先,由于TERMgnome-terminal 的变量的默认值为xterm,如果所有终端都没有偏差,那么我们什么也不做。但是,如果默认使用xterm条目的终端有偏差,则您必须找到一种方法来设置TERM变量;例如,假设这对于 gnome-terminal 是正确的。

获得此效果的最简单方法是使用参数启动 gnome-terminal--termname=gnome,例如,通过在 GNOME 面板上的启动器中适当地设置命令行。但是,如果您有旧版本,并且此方法不起作用,则可以添加以下行
if [ "$COLORTERM" = "gnome-terminal" ]
then
    export TERM=gnome
fi
到您的~/.bashrc配置文件[2]。赋值仅在 gnome-terminal 下执行,并正确设置TERM变量。

Note

将终端设置为gnome可能会阻止 ls 使用颜色,因为许多版本的 ls 不知道 gnome-terminal 具有颜色功能。为了避免这个问题,请创建一个配置文件~/.dircolors,使用 dircolors --print-database >~/.dircolors,并添加一行TERM=gnome到配置文件。

我们现在将动态生成一个适合有偏差的终端模拟器的 termcap 条目;这可以按如下方式完成,始终在~/.bashrc:
if [ "$TERM" = "gnome" ]
then
    export TERMCAP=$(infocmp -C gnome | grep -v '^#' | \
                    tr '\n\t' '  ' | sed 's/\\  //g' | sed s/::/:/g)
fi

最后,我们必须向终端设备解释擦除键生成哪个字符。由于通常擦除键应执行退格操作,因此有一个从 Red Hat 借鉴来的巧妙技巧/etc/bashrc,它有效:将此添加到~/.bashrc:
KBS=$(tput kbs)
if [ ${#KBS} -eq 1 ]; then stty erase $KBS; fi
这是一个简单的想法:我们从终端数据库中读取功能kbs,并将擦除字符设置为其值(如果它是单个字符)(这在标准终端和有偏差的终端中都会发生)。

Note

某些发行版可能已经在系统范围内的/etc/inputrc配置文件中进行了修复。在这种情况下,您可以从您的~/.inputrc.

6.3. 为 tcsh 修复

tcsh 的情况下,所有修复都放在~/.tcshrc中,并遵循与 bash 的修复程序相同的原理
bindkey "^[[3~" delete-char

if ($?COLORTERM) then
   if ($COLORTERM == "gnome-terminal") then
      setenv TERM gnome
   endif
endif

if ($?TERM) then
   if ($TERM == "gnome") then
      setenv TERMCAP \
       "`infocmp -C gnome | grep -v '^#' | tr '\n\t' '  ' | sed 's/\\  //g' | sed s/::/:/g`"
      bindkey "^?" delete-char
      bindkey "^[^?" delete-word
      bindkey "\377" delete-word
   endif
endif

set KBS=`tput kbs`
if (${%KBS} == 1) then 
   stty erase $KBS
endif
第二部分必须为每个有偏差的终端复制。当然,如果 termcap 条目已经存在,则无需生成它。

注释

[1]

在旧版本的 bash 上,您必须记住设置INPUTRC,例如添加
export INPUTRC=~/.inputrc
到您的~/.profile(或任何仅由登录 shell 读取的文件)。

[2]

更准确地说,是指在每个 shell 而不仅仅是登录 shell 中读取的 shell 配置文件。正确的文件取决于您的 bash 的启动顺序。