我经常开玩笑地将Unix描述为“喜欢打字的人的操作系统”。当然,它甚至有一个命令行的事实就是证明。但命令行用户不喜欢输入那么多。否则,为什么这么多命令会有这么短的名称,如 cp
、 ls
、 mv
和 rm
?事实上,命令行最珍视的目标之一就是懒惰—— laziness ;用最少的按键完成最多的工作。另一个目标是永远不必从键盘上抬起手指,伸手去拿鼠标。在本章中,我们将介绍使键盘使用更快、更高效的bash功能。
本章将出现以下命令:
clear
—— 清理屏幕history
—— 显示历史记录列表的内容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文档使用术语 killing 和 yanking 来指代我们通常所说的剪切和粘贴。被切割的项目被存储在一个名为 kill-ring 的缓冲区(内存中的临时存储区域)中。
下表描述了剪切和粘贴的键盘命令:
按键 | 动作 |
---|---|
Ctrl - k | 删除从光标位置到行尾的文本。 |
Ctrl - u | 删除从光标位置到行首的文本。 |
Alt - d | 删除从光标位置到当前单词末尾的文本。 |
Alt - Backspace | 删除从光标位置到当前单词开头的文本。 如果光标位于单词的开头,则删除前一个单词。 |
Ctrl - y | 从 kill-ring 缓冲区中删除(yank)文本并将其插入光标位置。 |
如果您冒险阅读bash手册页的“Readline”部分中的Readline文档,您将遇到术语 meta key 。在现代键盘上,这对应于 Alt 键,但并非总是如此。
在昏暗的时代(dim times —— 在PC之前,但在Unix之后),并不是每个人都有自己的电脑。他们可能有一个叫做终端的设备。终端是一种通信设备,它有一个文本显示屏和一个键盘,里面有足够的电子设备来显示文本字符和移动光标。它(通常通过串行电缆)连接到更大的计算机或更大计算机的通信网络。有许多不同品牌的终端,它们都有不同的键盘和显示功能集。由于他们都倾向于至少理解ASCII码,因此想要便携式应用程序的软件开发人员编写的是最低的通用标准。Unix系统有一种处理终端及其不同显示特性的复杂方法。由于Readline的开发人员无法确定是否存在专用的额外控制键,他们发明了一个,并称之为 meta 。虽然 Alt 键在现代键盘上用作元键,但如果您使用的是终端,您也可以按住 Esc 键以获得与按住 Alt 键相同的效果(在Linux中仍然可以这样做!)。
shell可以帮助我们的另一种方式是通过一种称为补全(completion)的机制。当我们在键入命令时按 Tab 键时,就会进行补全。让我们看看这是如何工作的。给定一个如下所示的主目录:
xxxxxxxxxx
[me@linuxbox ~]$ ls
Desktop ls-output.txt Pictures Templates Videos
Documents Music Public
尝试键入以下内容,但不要按 Enter 键:
xxxxxxxxxx
[me@linuxbox ~]$ ls l
现在按 Tab 键:
xxxxxxxxxx
[me@linuxbox ~]$ ls ls-output.txt
看到shell是如何为我们完成这行的吗?让我们试试另一个。同样,不要按 Enter 键。
xxxxxxxxxx
[me@linuxbox ~]$ ls D
按 Tab 。
xxxxxxxxxx
[me@linuxbox ~]$ ls D
没有补全,什么都没有。这是因为 D
与目录中的多个条目匹配。为了成功完成,我们给出的“线索”(clue)必须是明确的。如果连按两次 Tab ,会列出所有以 D
开头的文件供参考。
如果我们按照以下方式更进一步:
xxxxxxxxxx
[me@linuxbox ~]$ ls Do
然后按 Tab :
xxxxxxxxxx
[me@linuxbox ~]$ ls Documents
成功补全。
虽然这个例子显示了路径名的补全,这是它最常用的用法,但补全也适用于变量(如果单词的开头是 $
)、用户名(如果单词以 ~
开头)、命令(如果单词是行上的第一个单词)和主机名(如果单词开头是 @
)。主机名补全仅适用于 /etc/hosts 中列出的主机名。
如下表所示,有许多与补全相关的控制和元键序列。
按键 | 动作 |
---|---|
Alt - ? | 显示可能完成的列表。 一般情况下,可以通过再次按Tab键来完成此操作,这要容易得多。 |
Alt - * | 插入所有可能的补全。当您想使用多个可能的匹配时,这很有用。 |
还有不少相当模糊的。 bash
手册页中的“READLINE”下会出现一个列表。
最近版本的 bash
有一个称为可编程补全(programmable completion)的功能。可编程补全允许您(或更有可能是您的分发提供商)添加额外的补全规则。通常,这样做是为了添加对特定应用程序的支持。例如,可以为命令的选项列表添加补全,或匹配应用程序支持的特定文件类型。Ubuntu默认定义了一个相当大的集合。可编程补全是通过shell函数实现的,这是一种迷你shell脚本,我们将在后面的章节中介绍。如果你很好奇,试试以下方法:
set | less
看看你能不能找到它们。默认情况下,并非所有发行版都包含它们。
正如我们在第1章中发现的, bash
维护了已输入命令的历史记录。这个命令列表保存在我们的主目录中一个名为 .bash_history 的文件中。历史记录功能是一种有用的资源,可以减少我们必须做的键入量,特别是在与命令行编辑结合使用时。
在任何时候,我们都可以通过执行以下操作来查看历史列表的内容:
xxxxxxxxxx
[me@linuxbox ~]$ history | less
默认情况下,大多数现代Linux发行版都将bash配置为存储我们输入的最后1000个命令。我们将在第11章中看到如何调整此值。假设我们想找到我们用来列出/usr/bin的命令。这是一种方法:
xxxxxxxxxx
[me@linuxbox ~]$ history | grep /usr/bin
假设在我们的结果中,有一行包含一个有趣的命令,如下所示:
88 ls -l /usr/bin > ls-output.txt
88
是历史列表中命令的行号。我们可以立即使用另一种类型的扩展,称为历史扩展 —— history expansion 。要使用我们发现的行,我们可以这样做:
xxxxxxxxxx
[me@linuxbox ~]$ !88
bash将扩展 !88
进入历史列表中第88行的内容。还有其他形式的历史扩展,我们将在下一节中介绍。
bash还提供了增量搜索历史列表的能力。这意味着我们可以告诉bash在输入字符时搜索历史列表,每个额外的字符都会进一步优化我们的搜索。要开始增量搜索,请按 Ctrl - r ,然后按我们要查找的文本。当我们找到它时,我们可以按 Enter 键执行命令,也可以按 Ctrl - j 键将行从历史列表复制到当前命令行。要查找下一次出现的文本(向上移动历史记录列表),请再次按 Ctrl - r 。要退出搜索,请按 Ctrl - g 或 Ctrl - c 。在这里我们可以看到它的实际操作:
xxxxxxxxxx
[me@linuxbox ~]$
首先,按 Ctrl - r :
xxxxxxxxxx
(reverse-i-search)`':
提示更改表示我们正在执行反向增量搜索。它是“反向”(reverse)的,因为我们正在从“现在”到过去的某个时间进行搜索。接下来,我们开始键入搜索文本。在这个例子中, /usr/bin :
xxxxxxxxxx
(reverse-i-search)`/usr/bin': ls -l /usr/bin > ls-output.txt
搜索会立即返回我们的结果。根据我们的结果,我们可以按 Enter 键执行命令,也可以按 Ctrl - j 将命令复制到当前命令行进行进一步编辑。让我们复制它,按 Ctrl + j :
xxxxxxxxxx
[me@linuxbox ~]$ ls -l /usr/bin > ls-output.txt
我们的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打印扩展的结果,并将其放入命令历史记录中。这里有一个例子:
xxxxxxxxxx
[me@linuxbox ~]$ !ls:p
ls -l /usr/bin > ls-output.txt
现在该命令已被调用并作为历史列表上的最新项目放置,我们可以使用Up-Arrow 和 Return 或 !!
和 Return 执行它。
顺便说一句,历史扩展,如 !!
未记录在历史列表中,但其结果已记录。
历史扩展机制中有更多功能可用,但这个主题已经太神秘了,如果我们继续下去,我们的头脑可能会爆炸。bash手册页的【HISTORY EXPANSION】(历史扩展)部分介绍了所有血腥的(gory)细节。请随意探索!
除了bash中的命令历史功能外,大多数Linux发行版还包括一个名为 script
的程序,可用于记录整个shell会话并将其存储在文件中。命令的基本语法如下:
script [file]
其中 file 是用于存储记录的文件的名称。如果没有指定文件,则使用文件 typescript
(类型脚本)。有关程序选项和功能的完整列表,请参阅脚本手册页。
在本章中,我们介绍了shell提供的一些键盘技巧,以帮助铁杆(hardcore,硬核)打字员减少工作量。随着时间的推移,我们越来越多地使用命令行,我们可以参考本章来学习更多这些技巧。目前,将它们视为可选的,可能会有所帮助。