如何在 Linux 上使用 history 命令

Linux的shell会记录您执行过的命令历史,您可以通过搜索这些记录来重复执行之前的操作。一旦您熟练掌握Linux的历史命令及其使用方法,这将大大提高您的工作效率。

历史操作

正如乔治·桑塔亚那的名言所说,“那些不记得过去的人注定要重蹈覆辙。” 不幸的是,在Linux系统中,如果您不记得过去的操作,即使您想重复也无法实现。

这时,Linux的历史命令就显得尤为重要。它允许您查看并重复执行之前执行过的命令。这不仅仅是为了偷懒或节省时间,更重要的是为了提高效率和准确性。命令越长越复杂,就越难以记住和正确输入,而且容易出错。错误分为两种:一种是阻止命令执行,另一种是允许命令执行,但导致执行意料之外的操作。

history命令可以有效地解决这些问题。和大多数Linux命令一样,它的功能比您想象的要多。 如果您学会了如何使用history命令,这将提高您日常使用Linux命令行的效率。这是一项值得投资的时间。使用历史命令的方法远不止简单地重复按向上箭头。

基础命令

最基本的使用方法是直接输入history命令:

history

这将会在终端窗口中显示您之前使用过的命令列表。

这些命令会按照顺序编号,最近使用的命令(编号最大的)位于列表末尾。

要查看特定数量的命令,您可以在命令行上向history命令传递一个数字参数。例如,要查看您最近使用的10个命令,请输入:

history 10

您也可以通过管道将history命令的输出传递给tail命令 来获得相同的结果。为此,请输入:

history | tail -n 10

重复执行命令

如果要重复执行历史列表中某个命令,请输入感叹号 (!) 加上命令的编号,中间不要有空格。

例如,要重复执行第37条命令,您可以输入:

!37

要重复执行上一个命令,请输入两个感叹号,中间不要有空格:

!!

当您执行某个命令时忘记使用sudo时,这会非常有用。输入sudo、一个空格、两个感叹号,然后按Enter键。

例如,我们输入了一个需要sudo权限的命令。不需要重新输入整行,我们可以节省很多按键操作,只需要输入 sudo !!,如下所示:

mv ./my_script.sh /usr/local/bin/
sudo !!

因此,您可以通过输入列表中对应的数字来重复执行命令,也可以使用双感叹号来重复执行您使用的上一个命令。但是,如果您想重复执行第5条或者第8条命令呢?

您可以使用感叹号、连字符 (-) 和任意先前命令的编号(同样,不要有空格)来重复执行它。

要重复执行倒数第13条命令,您需要输入:

!-13

通过字符串搜索命令

要重复执行以某个特定字符串开头的上一个命令,您可以输入感叹号,然后输入该字符串,中间不要有空格,然后按Enter键。

例如,要重复执行以sudo开头的上一个命令,您可以输入:

!sudo

但是,这样做存在一定的风险。如果上一个以sudo开头的命令并不是您期望的那个,您将会执行错误的命令。

为了确保安全,您可以使用:p (打印) 修饰符,如下所示:

!sudo:p

这会指示历史命令将命令打印到终端窗口,而不是执行它。这样您可以在使用命令之前查看它。如果它正是您想要执行的命令,按向上箭头,然后按Enter键即可使用它。

如果想要查找包含特定字符串的命令,您可以使用感叹号和问号。

例如,要查找并执行第一个包含单词"aliases"的匹配命令,您可以输入:

!?aliases

这将找到任何包含字符串 "aliases"的命令,无论该字符串出现在命令中的哪个位置。

交互式搜索

交互式搜索允许您浏览匹配的命令列表并重复执行您想要的命令。

只需按下Ctrl+r即可开始搜索。

当您输入搜索提示时,第一个匹配的命令将出现。您输入的字母会出现在反引号 (`) 和撇号 (‘) 之间。匹配的命令会随着您输入每个字母而更新。

每次按下Ctrl+r时,将会向后搜索下一个匹配的命令,它会出现在终端窗口中。

当您按Enter键时,将执行显示的命令。

要在执行命令之前对其进行编辑,请按向左或向右箭头键。

该命令会出现在命令行上,您可以对其进行编辑。

您可以使用其他Linux工具来搜索历史列表。 例如,将历史记录的输出通过管道传递给grep搜索包含字符串的命令"aliases",您可以输入这个命令:

history | grep aliases

修改上一个命令

如果需要更正一个拼写错误,然后重复执行该命令,您可以使用插入符号 (^) 进行修改。每当您拼错命令或想要使用不同的命令行选项或参数重新运行命令时,这是一个非常好的技巧。

要使用它,请输入(不要有空格)一个插入符号、要替换的文本、另一个插入符号、替换文本、另一个插入符号,然后按Enter键。

例如,假设您输入了以下命令,不小心将"sshd"拼写成了"shhd"

sudo systemctl start shhd

您可以通过输入以下命令轻松更正此问题:

^shhd^sshd^

这将会将命令执行时,将"shhd"更正为"sshd"

从历史列表中删除命令

您还可以使用-d(删除)选项从历史列表中删除命令。没有理由将拼写错误的命令保留在历史列表中。

您可以使用grep找到它,使用-d选项将它的编号传递给history命令来删除它,然后再次搜索以确保它已被删除:

history | grep shhd
history -d 83
history | grep shhd

您还可以将一系列命令传递给-d选项。要删除从22到32(包括)的所有列表条目,请输入以下命令:

history -d 22 32

要仅删除最后五个命令,您可以输入一个负数,如下所示:

history -d -5

手动更新历史文件

当您登录或打开终端会话时,历史列表会从历史文件中读取。在Bash中,默认的历史文件是.bash_history

您在当前终端窗口会话中所做的任何更改,只会在您关闭终端窗口或注销时写入历史文件。

假设您想要打开另一个终端窗口来访问完整的历史列表,包括您在第一个终端窗口中输入的命令。-a(全部) 选项允许您在打开第二个终端窗口之前,在第一个终端窗口中执行此操作。

要使用它,请输入:

history -a

该命令会静默地写入历史文件。

如果要将历史列表的所有更改写入历史文件(例如,如果您删除了一些旧的命令),您可以使用 -w(写入) 选项,如下所示:

history -w

清除历史列表

要从历史列表中清除所有命令,您可以使用-c(清除)选项,如下所示:

history -c

如果您也想要强制对历史文件进行这些更改,请使用-w选项,如下所示:

history -w

安全性和历史文件

如果您使用任何需要在命令行输入敏感信息(例如密码)的应用程序,请记住这些信息也会保存在历史文件中。如果您不希望保存某些信息,可以使用以下命令结构立即将其从历史列表中删除:

special-app my-secret-password;history -d $(history 1)
history 5

此结构包含两个用分号 (;) 分隔的命令。让我们来分解一下:

special-app:我们正在使用的程序的名称。
my-secret-password:我们需要在命令行上为应用程序提供的秘密密码。这是命令一的结束。
history -d:在命令二中,我们调用历史命令的-d(删除) 选项。我们要删除的是命令的下一部分。
$(history 1):这里使用了命令替换。$()中包含的命令部分在子shell中执行。该执行的结果将作为文本输出到原始命令中。history 1命令返回上一个命令。 因此,您可以将第二个命令视为 history -d "last command here"

您可以使用history 5命令来确保包含密码的命令已从历史列表中删除。

但是,还有一种更简单的方法可以做到这一点。因为Bash默认会忽略以空格开头的行,所以只需要在行首包含一个空格,如下所示:

 special-app another-password
history 5

带有密码的命令不会添加到历史列表中。此技巧之所以起作用,是因为.bashrc文件中包含相关设置。

.bashrc文件

每次登录或打开终端窗口时都会执行.bashrc文件。它还包含一些控制历史命令行为的值。让我们使用gedit编辑器来编辑这个文件。

输入以下命令:

gedit .bashrc

在文件顶部附近,您会看到两个条目:

HISTSIZE:历史列表可以包含的最大条目数。
HISTFILESIZE:历史文件可以包含的最大行数限制。

这两个值以以下方式相互作用:

当您登录或启动终端窗口会话时,历史列表将从.bash_history文件中填充。
当您关闭终端窗口时,在HISTSIZE中设置的最大命令数将保存到.bash_history文件中。
如果启用了histappend shell选项,则命令会附加到.bash_history。如果未设置histappend,则会覆盖.bash_history
将历史列表中的命令保存到.bash_history后,历史文件将被截断为不超过HISTFILESIZE行。

同样在文件顶部附近,您会看到HISTCONTROL值的条目。

您可以设置此值以执行以下任何操作:

ignorespaces:以空格开头的行不会添加到历史列表中。
ignoredups:重复的命令不会添加到历史文件中。
ignoreboth:启用以上两项。

您还可以列出您不希望添加到历史列表中的特定命令。 用冒号 (:) 分隔这些内容,并将它们放在引号 (“…”)中。

您将按照此结构在.bashrc文件中添加一行,并替换您希望被忽略的命令:

export HISTIGNORE="ls:history"

使用时间戳

如果要将时间戳添加到历史列表中,可以使用HISTIMEFORMAT设置。为此,您只需在.bashrc文件中添加如下一行:

export HISTTIMEFORMAT="%c "

请注意,右引号前有一个空格。这可以防止时间戳与命令列表中的命令紧贴在一起。

现在,当您运行 history命令时,您将看到日期和时间戳。请注意,在添加时间戳之前,历史列表中的任何命令都将使用第一个接收时间戳的命令的日期和时间进行时间戳。在下面显示的示例中,这是命令118。

这是一个非常详细的时间戳。但是,您可以使用%c以外的标记来改进它。您可以使用的其他标记是:

%d: 天
%m: 月
%y: 年
%H: 小时
%M: 分钟
%S: 秒
%F: 完整日期(年-月-日格式)
%T: 时间(时:分:秒格式)
%c: 完整的日期和时间戳(日-日-月-年,时:分:秒格式)

让我们尝试使用一些不同的标记:

export HISTTIMEFORMAT="%d n%m %T "

输出使用日、月和时间。

但是,如果我们删除日期和月份,它将只显示时间。

您对HISTIMEFORMAT所做的任何更改都会应用到整个历史列表。之所以能够这样做,是因为每个命令的时间都存储为从Unix纪元开始的秒数HISTTIMEFORMAT指令仅指定用于将该秒数呈现为人类可读样式的格式,例如:

export HISTTIMEFORMAT="%T "

我们的输出现在更易于管理。

您还可以使用 history命令进行审计。 有时,查看您过去使用过的命令可以帮助您确定可能导致问题的原因。

就像在生活中一样,在Linux上,您可以使用history命令重温美好时光并从错误中吸取教训。