简介: GNU Emacs 有很多“神奇”的功能。常言说“每一个 hacker 都有一个自己的 GNU Emacs”。这个事实在很大程度上得益于人们能够按照 完全自我的方式去使用 GNU Emacs。将 Shell 运行在 GNU Emacs 里面就是众多的用法之一。在 GNU Emacs 里面运行 Shell 有很多种不同 的方法。包括各种各样的终端模拟。但是在笔者的工作当中更多的使用的是 Shell-mode 的方式。在这种方式下,可以最大限度的利用 GNU Emacs 所具有的各种神奇能力,让日常工作变得前所未有的轻松、有趣。 GNU Emacs 是一个非常强大的编辑器,这个编辑器不仅可以用来写文章,写程序,更重要的是,他可以和一些原本看似没有明显关系的应用 程序在一起,合作创造出一些新的“不可思议”的应用。比如说可以在 GNU Emacs 里面运行你的 Shell。 通常来说人们在 Linux 或者 Unix 上面工作的时候,不论是在本机工作,还是登录到地球另一头的远端机器,都是使用各种各样的终端或者 终端模拟器来运行 Shell。最常见的例如 xterm,rxvt,以及 Putty 之类的终端模拟器。与此对应,GNU Emacs 也有自己的终端模拟器,例 如 ansi-term,multi-term 等等。这些终端模式,使得你可以像在在其他终端当中一样工作,甚至可以在 Emacs 的终端里面运行 Vim。 但是,今天要和大家分享的是另外一种使用方式—— Shell mode。这是一种完全不同的工作方式。这种方式和大家常用的工作方式最大的一个 区别,就是在这里完全没有任何 terminal 的存在。用户实际上是工作在一个 Emacs 的文本缓冲区里面,并不直接和 Shell 进行交互。一 切的命令输入都是写入到这个文本缓冲区当中,经由 comint.el从缓冲区中读取,然后转交给后台的 Shell 进程。Shell 产生的输出再由 comint.el进行收集,然后写入到用户所用的这个缓冲区当中来。这个缓冲区在 Emacs 当中叫做 Shell 缓冲区 (Shell buffer)。 启动一个 Shell 缓冲区并且进入 shell mode 的过程非常简单。只需要在 Emacs 当中按下 Meta-x 组合键(在现在的键盘上通常是 Alt-x 组合键),然后输入命令 shell 并回车,Emacs 就会启动一个 Shell 进程并且打开一个与之关联的 Shell 缓冲区。Shell 缓冲区的名字通 常会是 *shell*。具体启动什么样的 Shell 进程通过 Emacs 配置文件里的 shell-file-name 变量指定,或者由用户的环境变量 SHELL 或 EMACSSHEL 来指定。通常的写法是 通常在人们的工作当中都会打开多个终端,同时进行几份工作。在这个时候就需要对这些终端窗口进行排列和管理(在这里假设你工作在图 形化环境之下)。而且通常需要频繁的使用鼠标在不同的窗口之间切换焦点。为了避免窗口之间相互遮盖,你也许会通过精心编辑的 .Xdefaults文件使得两个或四个终端窗口恰到好处的平铺在整个屏幕当中。但是仍然需要使用鼠标在不同的窗口进行切换,在不同的窗口之 间复制粘贴信息……这些窗口维护的工作在任务繁忙的时候会很繁重。并且如果这时候需要的不止 4 个窗口,或者你还需要进行额外的文字编 辑的工作……最终窗口还是会要么被覆盖起来,要么被挤到别的虚拟桌面。 在这种时候最好来试试 GNU Emacs。GNU Emacs 天生具有完善的窗口管理功能,并且完全不依赖于 X Window。这是因为 GNU Emacs 的诞生 要远远早于 X Window 的历史。在 GNU Emacs 里面你只需要按下 Ctrl-x 2 组合键就可以把当前窗口切分成上下两个等分的窗口, 当你使用两个或以上的窗口的时候,可以使用 Ctrl-x o(注意是小写字母 o)组合键在各个窗口进行移动。通过给 Ctrl-x o组合键加上数 字前缀,例如 Ctrl-u 3 Ctr-x o 或者更加简洁的 Meta-3 Ctrl-x o 就可以在多个窗口之间快速的移动。 当然,当你启动了太多各种缓冲区的时候,总归是要把其中的一些覆盖掉的。因为保证工作窗口具有足够的可视面积才是真正有意义的事。 在这种时候可以通过 Ctrl-x b 组合键在所有缓冲区之间方便的切换。或者通过 Ctrl-x Ctrl-b 组合键得到所有缓冲区的列表。 这种缓冲区的切换和 X Window 窗口或者虚拟桌面之间的切换最大的不同在于——如果你有任意两个或者多个缓冲区的工作需要相互参照(这 样的需要会非常常见),甚至就是信息的复制粘贴,这个时候相关的工作窗口最好能分布在同一个屏幕上。在 GNU Emacs 当中你将很容易把 这些需要参照的缓冲区切换到同一个屏幕的窗口当中去。而在图形终端的工作方式下,这些需要参照的窗口常常要么恰好是相互覆盖的,要 么恰好是处在不同的虚拟桌面之中,频繁的拖拽移动将会变得非常繁琐。 还有一种情况,由于工作的原因恰好需要对同一个 Shell 进程当中的内容进行上下文参照……通常绝大多数终端都不提供这种功能。但是在 Emacs 里面,同一个缓冲区显示在两个独立的窗口里面完全不成问题。 另外如果你很喜欢多个虚拟桌面的工作方式,可以使用 make-frame 命令生成多个 frame( 也许可以叫做“窗框”),把他们放到多个虚拟桌面 当中去。而且即使是在这种情况下,仍然可以使用 Ctrl-x b 组合键在任何一个 frame 中的任何一个窗口中切换到任何一个被遮盖的缓冲区 。不需要进行任何 X Window 当中的窗口移动和桌面切换,包括进行上下文参照。 我在上文当中提到了那么多的窗口,但是如果你在 minibuffer 当中第二次输入 Meta-x shell 命令,GNU Emacs 会把你带到已经存在的那 个名叫 shell 的 Shell 缓冲区,而不是创建一个新的。解决的方法非常简单——你只需要使用 rename-buffer 命令为现有的 Shell 缓冲 区重新安排一个名字,然后再执行 shell 命令,GNU Emacs 就会为你创建一个新的名叫 shell 的 Shell 缓冲区了。因为这两个命令在我 的工作中用的非常频繁,所以我把它们绑定到了两个快捷键上面 上文提到过,Ctrl-x 0, Ctrl-x 1, Ctrl-x 2, Ctrl-x 3 能够快速的更改 GNU Emacs 的窗口设置,但是如果我在用过 Ctrl-x 1 之后希望 能够快速“退回”到“刚才”使用过的窗口设置,而不是把它再做一遍,有没有办法做呢?GNU Emacs 有一个叫做 winner-mode 的 minor mode 可以帮你完成这个愿望。 只需要在你的 Emacs 配置文件里面加入下面几行 上文描述了在 GNU Emacs 里面通过简单的窗口管理优化 Shell 工作的方法,是不是开始对 Shell 从终端里面搬到 Emacs 里面开始有了一 点点的心动了呢?别着急,这还只是个开始,目前你看到的都还只是外表。接下来让我们和 Emacs 来一个甜蜜的约会吧。 我在开头的引子部分曾说过,在 Shell mode 中工作的时候,用户实际上接触的是一个文本缓冲区,实际上并没有直接的跟 Shell 进程打任 何交道。这也是和通常的终端模式的工作方法的一个非常大的区别。虽然这个区别看起来似乎不是那么显著(那是因为这个 Shell 缓冲区被 设计成了看起来很像一个图形终端的样子),但是实际上这点区别将会带来一些不可替代的优势。让我们来先看一个简单的例子: 让我们在 Shell 提示符前输入这样一行命令 这是一件很有意思的事情,因为我们并没有像在终端当中常见的那样在 Shell 提示符的后面进行命令输入,而是在一个看起来非常随意的地 方。神奇的是他居然被正确地执行了。事情的真相其实很简单。 因为现在我们是在一个被称作 Shell 缓冲区的文本缓冲区里面。这就是一个很普通的文本缓冲区,它具有所有其他文本缓冲区所具有的一切 特性。你可以在任何时候,任何位置,对这个缓冲区里的任何文本内容进行任何编辑。因为他就是文本。直到某一刻,你在其中一个文本行 上面按下了回车,这时 comint.el 就会负责把当前光标所在行的内容提取出来,发送给 Shell 去执行,然后将 Shell 执行的结果以及一个 提示符(这个提示符实际上也是由 Shell 输出给 comint.el 的)以文本的形式添加到这个缓冲区的末尾。 这个例子并不仅仅是列一个目录那么简单,事实上他提供了一个更加强大的工作方式 —— 曾经只能用来阅读的命令输出现在也可以被用来构 造新的命令了。让我们再来看一个新的例子,在这个例子中我们将把这种能力与 Bash 的历史命令引用的能力结合起来 2 : 2045 : 15:16:49 : /usr/share/emacs/23.1 dove@bash-4.1$ cd ../site-lisp && !! cd ../site-lisp && ls -1 auctex auctex.el autoconf autoconf-mode.el autotest-mode.el bashdb.el bashdb.elc 2 : 2045 : 15:16:49 : /usr/share/emacs/23.1 dove@bash-4.1$ cd ../site-lisp && !! cd ../site-lisp && ls -1 auctex head auctex.el autoconf autoconf-mode.el autotest-mode.el bashdb.el bashdb.elc 2 : 2046 : 15:17:16 : /usr/share/emacs/site-lisp dove@bash-4.1$ head auctex.el ;;; auctex.el ;; This can be used for starting up AUCTeX. The following somewhat ;; strange trick causes tex-site.el to be loaded in a way that can be ;; safely undone using (unload-feature 'tex-site). (autoload 'TeX-load-hack (expand-file-name "tex-site.el" (file-name-directory load-file-name))) (TeX-load-hack) 2 : 2047 : 15:23:53 : /usr/share/emacs/site-lisp dove@bash-4.1$ 如果你登录在一台远程机器上工作,cat 一个文件后,需要把这个文件的内容保存到本地来,那么完全不需要启动一个 FTP session 去下载 这个文件。你只需要选中缓冲区里面的文件内容,按下 Meta-x 组合键,输入 write-region 命令就可以把选中的内容保存在本地文件当中