shell 处于“vi”模式还是“emacs”模式是什么意思?

Gee*_*eek 35 command-line shell vim keyboard-shortcuts vi-mode

这个问题直接来自答案。在这种情况下,我特别无法理解以下部分:

在这方面,它的行为比 bash(readline)/ksh/zsh emacs 模式更接近 emacs,但与终端驱动程序嵌入式行编辑器(在规范模式下)不同,在那里Ctrl-W删除了前一个词(werase,也在 vi )。

这里我们谈论的是 shell 而不是编辑器,这是两个完全不同的程序。说 shell 处于某种编辑器模式是什么意思?

PS:您可以在我了解 shell 是什么以及如何使用 vim 进行基本编辑的前提下回答您的问题。

max*_*zig 29

在“vi”模式下,您可以像 vi 编辑器中的一行一样在当前 shell 提示上编辑/导航。您可以将其视为单行文本文件。类似地,在“emacs”模式下,您可以使用(一些)Emacs 的快捷方式来编辑/导航当前命令行。

例子

例如,在 vi 模式下,您可以执行以下操作(在 bash 中):

$ set -o vi
$ ls hello world
<ESC>
bbdw # results in
$ ls world
Run Code Online (Sandbox Code Playgroud)

在 emacs 模式下,您可以点击例如Ctrl+A跳转到一行的开头(vi: Ctrl+ [, 0or ESC, 0)。您可以通过set -o emacs(在 bash、ksh、zsh 等中)打开 emacs 模式。

阅读线

许多交互式命令行程序(包括bash)使用readline库。因此,您可以在一个地方配置要使用的输入模式(vi 或 emacs)和其他选项,这样每个使用 readline 的程序都具有完全相同的编辑/导航界面。

例如,我的 readline 配置如下所示:

$ cat ~/.inputrc 
set editing-mode vi
set blink-matching-paren on
Run Code Online (Sandbox Code Playgroud)

例如,据我所知,zsh / ksh不使用 readline,但也支持与 bash/readline 非常相似的 vi/emacs 模式。

当然,命令行 shell 中的 vi/emacs 模式只是完整编辑器功能集的一个子集。并非每个功能在命令行 shell 中都有意义,并且某些功能比其他功能更难以支持。

规范模式

在“发明”交互式命令行 shell 的 vi/emacs 模式之前,您的 shell 将仅使用终端的规范模式,该模式仅提供一组有限的编辑命令(例如Ctrl+W删除最后一个单词。

  • @limovala,应该是一个很好的近似值。当然取决于您的外壳 - 如果 CTL+A 不起作用,另一种可能性是您的外壳不包含任何编辑模式。也许某些 shell 还实现了其他编辑模式。但在实践中,你的方法应该足够好。您还可以在此之后使用 vi 命令进行测试以更加确定。在 bash 中你也可以使用类似 `set -o | 的东西。grep 'emacs\|vi'`。但是,在 zsh(我有 vi 模式的地方)中,这不起作用。 (2认同)

Sté*_*las 25

您会注意到,当您cat在终端上的 shell 提示符下运行时,cat应该将它从 stdin 读取的内容写入 stdout,然后按a,您会看到a终端驱动程序回显,但cat没有写入a(您看到只有一个a,终端驱动程序响应的那个)。

但是,如果您键入a Backspace b Enter,则不会看到cat输出a\010b\015,而是b\012(b和换行符)。

那是因为终端驱动程序(我们说的是内核中的软件,而不是像 那样的终端模拟器xterm)在规范模式下实现了一个非常基本的行编辑器。可以使用系统调用来配置终端驱动程序,就像使用命令一样。例如,要离开规范模式,您可以执行. 如果你这样做:ioctl()sttystty -icanon

stty -icanon; cat
Run Code Online (Sandbox Code Playgroud)

然后,您将同时看到echo(您可以使用 禁用stty -echo)和cat输出。

该编辑器是行编辑器。也就是说,它是由用户编辑一行文本,直到它被发送到读取终端设备的应用程序时按下Enter

该编辑的编辑能力非常有限。在大多数实现中,只有 4 个编辑键(实际上是字符)也可配置为stty

  • 擦除(^H^?通常):擦除前一个字符
  • 杀死(^U通常):清空(杀死)到目前为止输入的行
  • wease( ^W):删除前一个单词
  • lnext( ^V):按字面输入下一个字符(取消以上所有特殊含义)

过去,人们认为终端驱动程序行编辑器将扩展为更高级的功能。这就是为什么早期的 shell 都没有任何命令行编辑功能的原因(在 shell 提示符下您将获得与cat我们上面运行时相同的行编辑功能)。

然而,这真的从来没有发生过,可能部分原因是不同终端在按下某些按键时没有发送相同字符的混乱情况,这显然不应该在内核空间中实现。

因此,一些 shell 开始放弃终端驱动程序的规范模式并实现自己的行编辑器。当时,emacsvi是最流行的视觉文本编辑器,具有完全不同的键绑定和操作模式。在 中vi,您有一种输入文本模式和一种编辑模式。在 中emacs,您始终处于输入文本模式,但编辑是通过按组合键完成的(例如^b向后移动字符)。

当时的 shell 没有必要提出自己不同的键绑定。这会导致人们不得不学习另一种方法而感到沮丧。但是,选择一种(emacsvi)样式而不是另一种样式肯定会疏远其他编辑器的用户。

根据https://www.usenix.org/legacy/publications/library/proceedings/vhll/full_papers/korn.ksh.a

ksh 流行的内联编辑功能(vi 和 emacs 模式)是由贝尔实验室的软件开发人员创建的;Pat Sullivan 的 vi 行编辑模式和 Mike Veach 的 emacs 行编辑模式。每个人都独立修改了 Bourne shell 以添加这些功能,并且两个组织都希望仅当 ksh 具有各自的内联编辑器时才使用 ksh。最初在 ksh 中添加命令行编辑的想法被拒绝,希望行编辑能够进入终端驱动程序。然而,当很明显这不太可能很快发生时,两种行编辑模式都被集成到 ksh 中并成为可选的,这样它们就可以在提供编辑作为终端界面一部分的系统上禁用。

因此,相反,他们同时实现了一个界面,供用户在两者之间进行选择。ksh很可能是 80 年代初的第一个(重用单独编写的代码,将 vi 模式和 emacs 模式添加到 Bourne shell,如上所示),然后是tcshtcsh最初只有emacs键绑定,vi模式是后来添加的)和后来bash并且zsh在 90 年代初。

您可以在两种模式之间进行切换bashzshkshset -o viset -o emacs,与bindkey -ebindkey -vtcshzsh

POSIX 实际上指定了vi模式而不是emacs模式sh(故事说理查德斯托曼反对 POSIX 指定emacs模式sh)。

的默认模式bashksh(pdksh、mksh、oksh)的公共域变体,tcsh并且zsh是 emacs 模式(尽管使用zshvi如果您$EDITORvi),而在 AT&T 中ksh,除非或提及或,否则为模式。$EDITOR$VISUALviemacs

ksh后来还添加了一种gmacs模式,以适应不同emacs处理方式的 Gosling 用户Ctrl+T

现在处理^Winemacs或 in tcshemacs 模式可能早于werase终端行编辑器中的字符,所以我们不能真的为此责怪他们,我关于“离开......”的陈述可能会被视为误导。只是我觉得当你输入时像emacstcshinfo表现得与其他任何东西不同时它很烦人Ctrl-W。您可以想象,当您键入 Ctrl-W.

  • 感谢您提供出色的历史背景。遗憾的是,当时终端驱动程序中没有添加更复杂的内联编辑功能。程序不需要包含 Readline 等库。我还想知道为什么 POSIX 没有指定 Emacs-mode,因此到基本原理的链接很有趣。(我也分享了您对“^W”关闭窗口的挫败感)。 (2认同)