当前位置:首页>Linux>每天学一个Linux命令系列(36):history - 历史命令管理,别再用上箭头翻了

每天学一个Linux命令系列(36):history - 历史命令管理,别再用上箭头翻了

  • 2026-10-11 07:05:10
每天学一个Linux命令系列(36):history - 历史命令管理,别再用上箭头翻了
运
运维少年 · 科技观察

这个命令是干啥的

刚做运维那会儿,我有个坏习惯:执行过的命令全靠脑子记。后来次数多了,每次找之前执行过的一条命令,就疯狂按上箭头,一下、两下、十几下...有时候按过了还得再按回来。特别是一天下来敲了几百条命令的时候,想找回20分钟前执行的那个复杂sed替换,能按到手抽筋。

history 命令就是解决这个问题的。它会把你当前shell里执行过的所有命令都记录下来,还能让你通过简单的数字编号或者关键字搜索,快速找到并重新执行之前用过的命令。

说白了,这就是你的命令行时光机。

基本用法(3分钟上手)

查看历史记录

直接敲 history 就能看到所有记录:

# 查看历史命令列表,前面带编号
history

输出长这样:

 1001  ls -la
 1002  cd /var/log
 1003  tail -f syslog
 1004  vim /etc/nginx/nginx.conf
 1005  systemctl restart nginx

通过编号重复执行

看到编号了吧?想重新执行第1003条,不用再敲一遍:

# 重复执行编号为1003的历史命令
!1003

执行上一条命令

# 重复执行上一条命令
!!

这个超级实用。比如你 sudo apt update 完了发现忘了加sudo:

# 先用普通用户执行,发现权限不够
apt update
# 直接用sudo重复上一条
sudo !!

使用上一条命令的最后一个参数

# 引用上一条命令的最后一个参数
!$

场景:你先 cat /etc/nginx/sites-available/default 看了配置,然后想vim编辑它:

# 先看文件内容
cat /etc/nginx/sites-available/default
# 再用vim打开同一个文件,!$ 就是上一条命令的最后一个参数
vim !$

限制显示条数

# 只看最近20条
history 20

进阶骚操作

Ctrl+R 反向搜索

这是我用最多的功能。当你记不清某条命令的具体内容,只记得里面有个关键词:

按 Ctrl + R,然后输入关键词,shell会自动匹配最近一条包含这个关键词的命令。

(reverse-i-search)`nginx': vim /etc/nginx/nginx.conf

看到匹配的命令后,按回车就直接执行。如果想换一条更早的,继续按 Ctrl + R 切换。

给历史命令加时间戳

默认的 history 只显示编号和命令,不显示时间。想看到每条命令是什么时候执行的,需要设个环境变量:

# 给历史命令加上时间戳,格式为 年-月-日 时:分:秒
export HISTTIMEFORMAT='%F %T '

然后 history 输出就变成:

 1001  2024-01-15 09:23:45 ls -la
 1002  2024-01-15 09:24:01 cd /var/log

如果想让这个生效持久化,把这行加到 ~/.bashrc 里。

搜索历史命令

除了 Ctrl+R,还可以用 grep 搭配 history:

# 搜索包含 docker 的所有历史命令
history | grep docker

# 搜索 git 相关的命令,忽略大小写
history | grep -i git

控制历史记录的大小

# 设置历史文件最多保留 10000 条命令
export HISTFILESIZE=10000

# 设置当前会话最多记录 5000 条命令
export HISTSIZE=5000

这两个变量不一样:
- HISTSIZE:当前会话在内存中保留多少条
- HISTFILESIZE:~/.bash_history 文件里保存多少条

不记录某些命令

有些命令我不想进历史记录,比如密码相关的:

# 以空格开头的命令不记录到历史
export HISTCONTROL=ignorespace

这样你敲 mysql -u root -p (注意前面有个空格),这条命令就不会出现在 history 里。

更狠一点,指定某些命令永远不记录:

# 不记录 exit、ls、fg、bg 这些无用命令
export HISTIGNORE='exit:ls:fg:bg:history:clear'

清除历史记录

# 清除当前会话所有记录
history -c

# 把清除同步到历史文件
history -w

避坑指南

坑1:多终端覆盖问题

踩过最惨的一个坑:开了两个终端,A终端敲了半天,退出后历史命令正常保存。然后B终端退出,把A终端的记录全覆盖了。

原因:默认情况下,shell退出时覆盖写入 ~/.bash_history,而不是追加。

解决办法,加到 ~/.bashrc:

# 让每个命令执行后立即追加到历史文件,而不是退出时才写入
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"

# 退出时合并历史记录,而不是覆盖
shopt -s histappend

加了这两行之后,多终端就互不干扰了。

坑2:历史文件被撑爆

有次我在生产服务器上查问题,狂敲了几万条命令排查。结果一看 ~/.bash_history 已经几十MB了。倒不是说多大影响,但 history 命令明显卡了。

解决办法就是合理设置 HISTFILESIZE,别舍不得删。

坑3:敏感命令泄漏

直接在命令行里输密码(比如 mysql -u root -p123456),这条命令会明码保存在 ~/.bash_history。解决方法:
1. 永远不要在命令里直接写密码
2. 万一写了,赶紧 history -c 清掉
3. 或者设 HISTCONTROL=ignorespace,前面加空格

坑4:! 命令在脚本里的问题

写shell脚本时,千万别用 !! 和 !$。脚本里 ! 有特殊含义,会被转义成历史扩展,轻则报错,重则执行了意料之外的命令。

实战场景(重点!结合真实运维场景)

场景1:事故复盘

生产环境出问题了,需要排查谁在什么时间执行了什么操作。

# 先给历史命令加上时间戳
export HISTTIMEFORMAT='%F %T '

# 查看某段时间内的操作
history | grep "2024-01-15 09:2"

# 配合 sudo 日志,基本能还原事故现场

我一般还会把所有人的 .bash_history 集中搜集到日志服务器,配合 HISTTIMEFORMAT 做安全审计。

场景2:快速恢复复杂命令

比如之前调试容器网络时,花了很多时间拼出一条复杂的 iptables 规则:

# 搜索历史中的iptables命令
history | grep iptables

# 找到编号后直接执行
!888

如果这条命令在好几个会话之前执行的,甚至昨天执行的,上箭头根本翻不到。这时候 Ctrl+R 或者 history | grep 就救命了。

场景3:快速复用长路径

# 第一次敲长路径
cd /var/www/project/logs/nginx/access/

# 查看这个目录
ls -la !$

# 压缩它
tar -czf backup.tar.gz !$

场景4:批量重复执行

有次需要重启10台服务器上的某个服务,在历史里找到了重启命令:

# 找到编号
history | grep restart

# 在跳板机上循环执行
for i in server{01..10}; do
    ssh $i "!123"  # !123 就是那条 restart 命令
done

今日作业

小练习:执行以下几条命令后,用 history 配合 ! 操作符,在不重新输入的情况下重建一个目录结构。

mkdir -p /tmp/test-project
cd /tmp/test-project
touch README.md
touch index.html
ls -la

要求:
1. 用 !! 重复执行 ls -la
2. 用 !$ 新建一个 test.txt 文件在同一个目录
3. 用 history | grep 找到 mkdir 命令的编号,然后用 !编号 执行它

做完之后,运行 history | tail -10 截图看看你用了哪些技巧。

E N D

运维少年 · 科技观察

最新文章

随机文章