Linux history 命令相关使用以及配置
Linux history
新手学习 shell 的时候都知道 history 命令能帮助我们查看之前运行的命令集合,通过这个能够帮我们回忆之前的命令,以及进行各种排错等等。
比如我们直接输入 history 进行查看:
history [N]
history 5 # 仅仅显示最后5行
history 使用
history [N]
查看最后 5 条历史命令
history 5
history -c
清空历史命令
history -c
history -d offset
指定删除第几个命令的记录
history -d 100 # 删除第100条命令
history -anrw [filename]
-a 追加本次会话执行的命令历史列表,保存到历史文件中。
-n 将历史文件中新增的部分加载到内存中,可以方便多端同步。
-r 读取历史文件中的所有命令在内存中,即使已经加载过
-w 将历史文件写出到 [filename] 中
history -anrw /root/.bash_history
ps: 使用 man 命令可以查看 history 的详细使用
history -p arg [arg …]
进行打印,但是不记录在历史记录中,有点像 echo arg[arg…] 但并不会被历史命令记录
history -p $HISTTIMEFORMAT
# 但如果有空格则会换行进行打印
history -s arg [arg …]
伪造命令,相当于直接添加这条命令到历史记录中,但并不会真正执行
history -s rm -rf /*
# 构造了一条 rm -rf /* 的命令
history 配置
HISTTIMEFORMAT hisotry 打印格式
如上面所示,我们在查看历史记录的时候,并没有记录这条命令的运行时间,但其实是可以配置的。
vim /etc/bashrc
# or
vim /etc/profile
# or
vim /etc/profile.d/history.sh #最推荐这个
# 在这些文件中追加
export HISTTIMEFORMAT="%Y-%m-%d %H:%M "
# 注意初次更改时,之前的命令会记录为更改的时刻。
可以看到,如果我们将 HISTTIMEFORMAT 更改为对应的 format 格式,那么 history 命令打印的格式也会变更。甚至我们可以在上面运行一些其他命令当做参数补充:
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S `who am i | awk '{print $1,$5}'` "
配置历史记录最大条数
之前的篇幅讲过,在我们的环境变量里面有一个变量可以更改我们 history 命令的最大长度,默认是 1000:
set |grep HISTSIZE # 定义的是 history 输出命令的记录数
# HISTSIZE=1000
set |grep HISTFILESIZE # 定义的是 .bash_history 中的记录总数
# HISTFILESIZE =1000
这个参数在 /etc/profile 中被定义:
cat /etc/profile |grep HISTSIZE
# HISTSIZE=1000
# export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL
可以看到,这个参数也是在 /etc/profile.d/* 之前被定义的,所以如果我们想更改也可以
echo 'export HISTSIZE=2000' >> /etc/profile.d/history.sh
echo 'export HISTFILESIZE=2000' >> /etc/profile.d/history.sh
chmod 755 /etc/profile.d/history.sh
HISTSIZE & HISTFILESIZE
HISTSIZE 标示在 history 命令中,要记录的命令数量
如果为 0, 则不进行记录
如果小于 0,则永远记录
如果大于 0,则仅记录这个数值
HISTFILESIZE 标示在历史文件 .bash_history 中的记录数。
如果为 0, 则不进行记录
如果小于 0,则永远记录
如果大于 0,则仅记录这个数值
当 shell 退出时,才会将缓存中的数据写出到这个文件。
HISTIGNORE
这个变量是运维比较头疼的环境变量,可以忽略某些常见命令,不保存在命令历史中。
export HISTIGNORE="pwd:df:du:rd*" # 以:为分隔符进行切分匹配
rd1
rd2
rd3
4rd
r5d
history | tail
可以看到,我们配置忽略 rd 开头的命令后,前面执行的三条命令不存在了,只剩下 4rd 和 r5d 两条命令。
HISTFILE
这个变量决定了我们的 history 文件写出在哪里,默认为本用户目录下的 .bash_history 文件。
echo $$HISTFILE
# ~/.bash_history
当然当我们启动 bash 的时候,变量 $HISTFILE 所指向的文件会被读取,让当前会话能够加载之前的历史命令。
histappend
if (history_lines_this_session <= where_history() || force_append_history)
append_history (history_lines_this_session, hf);
else
write_history (hf);
sv_histsize ("HISTFILESIZE");
当存储到文件时,Bash 会将此前会话中的命令直接存储到文件末尾,如果文件的记录数大于定义的最大记录数,则清空旧的历史命令,并且当下次再存储时会重写此前文件。
如果 histappend (force_append_history)设置是启动的,那么当前会话退出时,最后执行的 $HISTSIZE 行会被拷贝进 $HISTFILE 中,不考虑大小。
# 使用 shopt (shell option) 来查看 histappend 是否开启
shopt histappend
# histappend on
命令记录模式
存储操作最终还是归集于存储介质的读写操作,如对文件的读写,增加的只是对业务逻辑规则的各种限制。
命令可以在执行命令时记录,也可以在命令刚输入,但已经识别的情况下记录,Bash 属于后者。
Bash 在 yacc 做语法分析时将用户输入的命令通过 maybe_add_history 函数写入到当前会话的命令历史记录表中。
在做语法分析时就已经记录了用户输入的命令,此时记录就不用管命令最终的结果是怎样,也不用管如果执行过程出了异常会怎样处理。
它只是如实的在执行前记录用户输入的什么命令,由此,我们可以知道 Bash 的命令历史记录的定义为用户输入的命令历史记录。
多终端问题
我们知道相同的用户也可以在同一台服务器开启多个终端,那么这些终端都会产生不同的历史记录:
当我们用户退出当前会话的时候,才会把缓存中的内容写入到 ~/.bash_history 中,那么意味着如果我当前终端不释放,其他终端是感知不到我当前终端运行的命令。
~/.bash_history 在之前也讲过,是存储最后 $HISTFILESIZE 条历史命令的。
如果我们想要一个用户的多端都同步历史 shell 命令可以这样配置
export PROMPT_COMMAND='history -a;history -r;'
但十分不推荐这样做,因为很多时候其实我们并不希望多端同步,而且会花费较多性能。