第八章:高级键盘技巧

我经常开玩笑地将Unix描述为“喜欢打字的人的操作系统”。当然,它甚至有一个命令行的事实就是证明。但命令行用户不喜欢输入那么多。否则,为什么这么多命令会有这么短的名称,如 cplsmvrm ?事实上,命令行最珍视的目标之一就是懒惰—— laziness ;用最少的按键完成最多的工作。另一个目标是永远不必从键盘上抬起手指,伸手去拿鼠标。在本章中,我们将介绍使键盘使用更快、更高效的bash功能。

本章将出现以下命令:

第八章:高级键盘技巧命令行编辑光标移动修改文本剪切与粘贴(杀戮与攻击)文本元键补全可编程补全使用历史记录查找历史记录历史扩展脚本总结

命令行编辑

bash使用一个名为 Readline 的库(不同程序可以使用的例程的共享集合)来实现命令行编辑。我们已经看到了其中的一些。例如,我们知道箭头键可以移动光标,但还有更多功能。把这些看作是我们可以在工作中使用的额外工具。学习所有这些并不重要,但其中许多非常有用。根据需要选择。

注意:以下一些按键序列(特别是使用 Alt 键的按键序列)可能会被GUI拦截以用于其他功能。使用虚拟控制台时,所有按键序列都应正常工作。

光标移动

下表列出了用于移动光标的按键:

按键动作
Ctrl - a将光标移动到行首。
Ctrl - e将光标移动到行尾。
Ctrl - f将光标向前(forward)移动一个字符;与右箭头键相同。
Ctrl - b将光标向回(backward)移动一个字符;与左箭头键相同。
Alt - f将光标向前移动一个单词。
Alt - b将光标向回移动一个单词。
Ctrl - l清除屏幕并将光标移动到左上角。
clear 命令也会做同样的事情。

修改文本

由于我们在编写命令时可能会出错,因此我们需要一种有效的方法来纠正它们。下表描述了用于在命令行上编辑字符的键盘命令。

按键动作
Ctrl - d删除光标所在位置的字符。
Ctrl - t将光标位置的字符与前面(preceding)的字符进行转置(交换)。
Alt - t将光标位置处的单词与前面的单词互换。
Alt - l将光标位置到单词末尾的字符转换为小写。
Alt - u将光标位置到单词末尾的字符转换为大写。

剪切与粘贴(杀戮与攻击)文本

yank——猛拉、猛拽

Readline文档使用术语 killingyanking 来指代我们通常所说的剪切和粘贴。被切割的项目被存储在一个名为 kill-ring 的缓冲区(内存中的临时存储区域)中。

下表描述了剪切和粘贴的键盘命令:

按键动作
Ctrl - k删除从光标位置到行尾的文本。
Ctrl - u删除从光标位置到行首的文本。
Alt - d删除从光标位置到当前单词末尾的文本。
Alt - Backspace删除从光标位置到当前单词开头的文本。
如果光标位于单词的开头,则删除前一个单词。
Ctrl - ykill-ring 缓冲区中删除(yank)文本并将其插入光标位置。

元键

如果您冒险阅读bash手册页的“Readline”部分中的Readline文档,您将遇到术语 meta key 。在现代键盘上,这对应于 Alt 键,但并非总是如此。

在昏暗的时代(dim times —— 在PC之前,但在Unix之后),并不是每个人都有自己的电脑。他们可能有一个叫做终端的设备。终端是一种通信设备,它有一个文本显示屏和一个键盘,里面有足够的电子设备来显示文本字符和移动光标。它(通常通过串行电缆)连接到更大的计算机或更大计算机的通信网络。有许多不同品牌的终端,它们都有不同的键盘和显示功能集。由于他们都倾向于至少理解ASCII码,因此想要便携式应用程序的软件开发人员编写的是最低的通用标准。Unix系统有一种处理终端及其不同显示特性的复杂方法。由于Readline的开发人员无法确定是否存在专用的额外控制键,他们发明了一个,并称之为 meta 。虽然 Alt 键在现代键盘上用作元键,但如果您使用的是终端,您也可以按住 Esc 键以获得与按住 Alt 键相同的效果(在Linux中仍然可以这样做!)。

补全

shell可以帮助我们的另一种方式是通过一种称为补全(completion)的机制。当我们在键入命令时按 Tab 键时,就会进行补全。让我们看看这是如何工作的。给定一个如下所示的主目录:

尝试键入以下内容,但不要按 Enter

现在按 Tab 键:

看到shell是如何为我们完成这行的吗?让我们试试另一个。同样,不要按 Enter 键。

Tab

没有补全,什么都没有。这是因为 D 与目录中的多个条目匹配。为了成功完成,我们给出的“线索”(clue)必须是明确的。如果连按两次 Tab ,会列出所有以 D 开头的文件供参考。

如果我们按照以下方式更进一步:

然后按 Tab

成功补全。

虽然这个例子显示了路径名的补全,这是它最常用的用法,但补全也适用于变量(如果单词的开头是 $ )、用户名(如果单词以 ~ 开头)、命令(如果单词是行上的第一个单词)和主机名(如果单词开头是 @ )。主机名补全仅适用于 /etc/hosts 中列出的主机名。

如下表所示,有许多与补全相关的控制和元键序列。

按键动作
Alt - ?显示可能完成的列表。
一般情况下,可以通过再次按Tab键来完成此操作,这要容易得多。
Alt - *插入所有可能的补全。当您想使用多个可能的匹配时,这很有用。

还有不少相当模糊的。 bash 手册页中的“READLINE”下会出现一个列表。

可编程补全

最近版本的 bash 有一个称为可编程补全(programmable completion)的功能。可编程补全允许您(或更有可能是您的分发提供商)添加额外的补全规则。通常,这样做是为了添加对特定应用程序的支持。例如,可以为命令的选项列表添加补全,或匹配应用程序支持的特定文件类型。Ubuntu默认定义了一个相当大的集合。可编程补全是通过shell函数实现的,这是一种迷你shell脚本,我们将在后面的章节中介绍。如果你很好奇,试试以下方法:

set | less

看看你能不能找到它们。默认情况下,并非所有发行版都包含它们。

使用历史记录

正如我们在第1章中发现的, bash 维护了已输入命令的历史记录。这个命令列表保存在我们的主目录中一个名为 .bash_history 的文件中。历史记录功能是一种有用的资源,可以减少我们必须做的键入量,特别是在与命令行编辑结合使用时。

查找历史记录

在任何时候,我们都可以通过执行以下操作来查看历史列表的内容:

默认情况下,大多数现代Linux发行版都将bash配置为存储我们输入的最后1000个命令。我们将在第11章中看到如何调整此值。假设我们想找到我们用来列出/usr/bin的命令。这是一种方法:

假设在我们的结果中,有一行包含一个有趣的命令,如下所示:

88 ls -l /usr/bin > ls-output.txt

88 是历史列表中命令的行号。我们可以立即使用另一种类型的扩展,称为历史扩展 —— history expansion 。要使用我们发现的行,我们可以这样做:

bash将扩展 !88 进入历史列表中第88行的内容。还有其他形式的历史扩展,我们将在下一节中介绍。

bash还提供了增量搜索历史列表的能力。这意味着我们可以告诉bash在输入字符时搜索历史列表,每个额外的字符都会进一步优化我们的搜索。要开始增量搜索,请按 Ctrl - r ,然后按我们要查找的文本。当我们找到它时,我们可以按 Enter 键执行命令,也可以按 Ctrl - j 键将行从历史列表复制到当前命令行。要查找下一次出现的文本(向上移动历史记录列表),请再次按 Ctrl - r 。要退出搜索,请按 Ctrl - gCtrl - c 。在这里我们可以看到它的实际操作:

首先,按 Ctrl - r

提示更改表示我们正在执行反向增量搜索。它是“反向”(reverse)的,因为我们正在从“现在”到过去的某个时间进行搜索。接下来,我们开始键入搜索文本。在这个例子中, /usr/bin

搜索会立即返回我们的结果。根据我们的结果,我们可以按 Enter 键执行命令,也可以按 Ctrl - j 将命令复制到当前命令行进行进一步编辑。让我们复制它,按 Ctrl + j

我们的shell提示符返回,我们的命令行已加载并准备就绪!

下表列出了用于操作历史列表的一些按键。

按键动作
Ctrl - p移动到上一个(previous)历史条目。这与向上箭头的动作相同。
Ctrl - n移动到下一个(next)历史条目。这与向下箭头的动作相同。
Alt - <移动到历史记录列表的开头(顶部)。
Alt - >移动到历史列表的末尾(底部),即当前命令行。
Ctrl - r反向(reverse)增量搜索。
这将从当前命令行向上递增搜索历史列表。
Alt - p反向搜索,非增量。
使用此键,键入搜索字符串并按 enter 键,然后执行搜索。
Alt - n正向搜索,非增量。
Ctrl - o执行历史记录列表中的当前项目并前进到下一个。
如果我们试图重新执行历史列表中的一系列命令,这很方便。

历史扩展

shell通过使用 ! 为历史列表中的项目提供了一种特殊类型的扩展。我们已经看到感叹号后面可以跟一个数字来插入历史列表中的条目。如下表所示,还有许多其他扩展功能:

序列动作
!!重复上一个命令。按向上箭头进入可能更容易。
! number重复历史列表中编号为 number 的项目。
! string重复以 string 开头的上一个历史记录列表项。
!? string重复包含 string 的上次历史记录列表项。

小心使用 ! string!? string 形式,除非您绝对确定历史列表项的内容。我们可以通过在扩展后附加 :p 来缓解这个问题。这告诉shell打印扩展的结果,并将其放入命令历史记录中。这里有一个例子:

现在该命令已被调用并作为历史列表上的最新项目放置,我们可以使用Up-ArrowReturn!!Return 执行它。

顺便说一句,历史扩展,如 !! 未记录在历史列表中,但其结果已记录。

历史扩展机制中有更多功能可用,但这个主题已经太神秘了,如果我们继续下去,我们的头脑可能会爆炸。bash手册页的【HISTORY EXPANSION】(历史扩展)部分介绍了所有血腥的(gory)细节。请随意探索!

脚本

除了bash中的命令历史功能外,大多数Linux发行版还包括一个名为 script 的程序,可用于记录整个shell会话并将其存储在文件中。命令的基本语法如下:

script [file]

其中 file 是用于存储记录的文件的名称。如果没有指定文件,则使用文件 typescript (类型脚本)。有关程序选项和功能的完整列表,请参阅脚本手册页。

总结

在本章中,我们介绍了shell提供的一些键盘技巧,以帮助铁杆(hardcore,硬核)打字员减少工作量。随着时间的推移,我们越来越多地使用命令行,我们可以参考本章来学习更多这些技巧。目前,将它们视为可选的,可能会有所帮助。