![为什么 bash_history 总是出现相同的情况并且不使用非登录 shell 进行更新?](https://linux22.com/image/46113/%E4%B8%BA%E4%BB%80%E4%B9%88%20bash_history%20%E6%80%BB%E6%98%AF%E5%87%BA%E7%8E%B0%E7%9B%B8%E5%90%8C%E7%9A%84%E6%83%85%E5%86%B5%E5%B9%B6%E4%B8%94%E4%B8%8D%E4%BD%BF%E7%94%A8%E9%9D%9E%E7%99%BB%E5%BD%95%20shell%20%E8%BF%9B%E8%A1%8C%E6%9B%B4%E6%96%B0%EF%BC%9F.png)
在过去的几天里,我注意到每当我关闭系统(Debian 测试)并启动 bash 会话,然后按向上箭头键时,我都会收到第一次使用 清除历史缓存时的命令history -c
。我不确定这是怎么发生的,但即使我再次清除历史记录,然后按向上箭头,很好,它可以工作,但如果我启动另一个 shell,它就不会(每当我重新启动或关闭或注销时就更少了) 。
我已经尝试了一切(甚至手动删除.bash_history
),所以我没有想法了。
$ echo $SHELL
/bin/bash
$ /bin/bash --version
GNU bash, version 4.2.45(1)-release (i486-pc-linux-gnu)
$ echo $HISTFILE
/home/braiam/.bash_history
当寻找信息添加问题时,我跑了ls -l .bash_history
(不要看起来像个傻子),发现了问题:
$ ls -l .bash_history
-r--------. 1 braiam braiam 59372 Jul 26 20:18 .bash_history
但跑步chmod +w .bash_history
并没有挽救局面。现在我想知道事情怎么会这样结束......
删除.bash_history
文件后,我现在没有历史记录。我检查了 .bashrc 以寻找线索:
cat .bashrc | grep -i hist
# don't put duplicate lines or lines starting with space in the history.
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
按照 ash 的回答,在非登录(gnome-terminal)shell 中:
braiam@bt:~$ echo abacaba; echo $$
abacaba
15372
braiam@bt:~$
然后启动另一个非登录 shell:
braiam@bt:~$ strace -o e -s 256 -p 15372
Process 15372 attached - interrupt to quit
返回第一个 shell,然后输入history -a
:
braiam@bt:~$ echo abacaba; echo $$
abacaba
15372
braiam@bt:~$ history -a
braiam@bt:~$
在带有 strace 的 shell 中,什么也没有:
braiam@bt:~$ strace -oe -s 256 -p 15372 进程 15372 附加 - 中断退出
在这里我几乎不抱希望了,所以我决定看一下strace手册,发现是-o
将结果转储到文件中,所以cat e
返回这个:
cat e
read(0, "\33", 1) = 1
read(0, "[", 1) = 1
read(0, "A", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "history -w", 10) = 10
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "\33", 1) = 1
read(0, "[", 1) = 1
read(0, "A", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "\10a", 2) = 2
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "\r", 1) = 1
write(2, "\n", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigaction(SIGINT, {0x80a0e30, [], 0}, {0x80e9d00, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_IGN, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_IGN, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGALRM, {0x80a1080, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 0}, {0x80e9d00, [], 0}, 8) = 0
rt_sigaction(SIGTSTP, {SIG_IGN, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGTTOU, {SIG_IGN, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGTTIN, {SIG_IGN, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGWINCH, {0x80a09e0, [], 0}, {0x80e9550, [], SA_RESTART}, 8) = 0
rt_sigaction(SIGINT, {0x80a0e30, [], 0}, {0x80a0e30, [], 0}, 8) = 0
time(NULL) = 1378047084
stat64("/home/braiam/.bash_history", {st_mode=S_IFREG|0600, st_size=44, ...}) = 0
open("/home/braiam/.bash_history", O_WRONLY|O_APPEND|O_LARGEFILE) = 3
write(3, "history -w\nhistory -a\n", 22) = 22
close(3) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigaction(SIGINT, {0x80a0e30, [], 0}, {0x80a0e30, [], 0}, 8) = 0
time(NULL) = 1378047084
rt_sigprocmask(SIG_BLOCK, [CHLD TSTP TTIN TTOU], [], 8) = 0
ioctl(255, TIOCSPGRP, [15372]) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigaction(SIGINT, {0x80a0e30, [], 0}, {0x80a0e30, [], 0}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
ioctl(0, TIOCGWINSZ, {ws_row=24, ws_col=80, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(0, TIOCSWINSZ, {ws_row=24, ws_col=80, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT QUIT ALRM TERM TSTP TTIN TTOU], [], 8) = 0
rt_sigaction(SIGINT, {0x80e9d00, [], 0}, {0x80a0e30, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x80e9d00, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_IGN, [], 0}, {0x80e9d00, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {0x80e9d00, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_IGN, [], 0}, {0x80e9d00, [], 0}, 8) = 0
rt_sigaction(SIGALRM, {0x80e9d00, [], 0}, {0x80a1080, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 0}, 8) = 0
rt_sigaction(SIGTSTP, {0x80e9d00, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGTSTP, {SIG_IGN, [], 0}, {0x80e9d00, [], 0}, 8) = 0
rt_sigaction(SIGTTOU, {0x80e9d00, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGTTOU, {SIG_IGN, [], 0}, {0x80e9d00, [], 0}, 8) = 0
rt_sigaction(SIGTTIN, {0x80e9d00, [], 0}, {SIG_IGN, [], 0}, 8) = 0
rt_sigaction(SIGTTIN, {SIG_IGN, [], 0}, {0x80e9d00, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigaction(SIGWINCH, {0x80e9550, [], SA_RESTART}, {0x80a09e0, [], 0}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "\33]0;braiam@bt: ~\7\33[01;31mbraiam@bt\33[00m:\33[01;34m~\33[00m$ ", 56) = 56
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, <unfinished ...>
所以,按照这个说法,是没有问题的。然后,我打开另一个非登录 shell,却没有任何喜悦。历史记录未加载。 Acat .bash_history
显示文件确实已被填充,但非登录 shell 不接受它。
现在,我尝试了两者strace -o /tmp/e -s 512 bash
这里(对于字符限制来说太长)和strace -o /tmp/e -s 512 gnome-terminal
这里(均来自pastebin.com,抱歉)。这里使用原始设置(减去 .bash_history 上的 -w 权限)。
接下来我尝试登录,Ctrl + Alt + F1,登录,按向上箭头,交叉手指,它成功了!但是,这仍然让我疑惑,为什么非登录 shell 不加载历史记录?
答案1
你试过了history -c && history -w
吗?
history -c
清除历史函数的缓存并将history -w
命令写入.bash_history中历史函数的缓存(无)。
另一个选择是清除 bash 历史记录/dev/null > ~/.bash_history
并链接~/.bash_history
到/dev/null
:ln -sf /dev/null ~/.bash_history
如果您不想保存当前 shell 会话的命令,则必须运行history -r
将历史缓存重置为其初始状态(在启动会话之前)。然后注销,历史缓存上的命令(与启动 shell 会话之前相同)将被写入.bash_history
答案2
发生这种情况的原因之一是 shell 未正常退出,或者您在 shell 仍在运行时寻找更新。
要测试此场景,请尝试history -a
执行一些独特的命令,例如echo abacaba
在正在运行的 shell 上,然后启动一个新的 shell。如果新 shell 从第一个 shell 获取更新,则写入和读取历史文件就可以正常工作。但是,如果这不起作用,则说明有其他问题,我会亲自尝试strace
诊断。
另一件需要检查的事情是 HOME 变量没有更改,并且设置为passwd
与用户文件中设置的路径相同。
使用strace进行诊断
- 在一个壳里,
echo abacaba; echo $$
- 在另一个 shell 中,
strace -o e -s 256 -p $PID
, 其中$PID
=$$
第一个 shell 的输出 - 在第一个 shell 中,
history -a
- 停止 strace 并查看它的处理情况
history -a
;应该有 open() 和 write() 调用。
非交互式外壳
奇怪的是,非交互式 shell 没有获取 shell 历史记录,但这可以通过多种原因来解释。更多的诊断会有帮助。
如果可以修改非交互式 shell 的启动以插入 strace,则可以再次使用 Strace 来提供帮助。例如,以下显示了修改为使用 strace 的 shell 启动命令:
bash /home/jack/bin/jacks_script
strace -f -o /tmp/e -s 512 bash /home/jack/bin/jacks_script
当然,如果一次运行其中多个,/tmp/e
则会被覆盖。
使用grep open /tmp/e
,如果 shell 加载了 bash_history 文件,则应该显示该文件的完整路径。因此,此命令允许进行两项检查:(1) 历史文件是否正在打开和读取,以及 (2) 历史文件的路径是否符合预期。
没有痕迹
验证 shell 是否history
设置了选项(set -o history
对于 bash)。
不清楚的一件事是HISTFILE
shell 何时检查。例如,如果在 中设置.bash_profile
,我不确定它是否会影响 shell 历史记录的读取,因为它是在 shell 启动之后,但在向用户提供第一个命令提示符之前。
答案3
您只需取消设置$HISTFILE
(其中包含历史文件的路径),这不会影响您在当前会话中使用历史记录的能力:
unset HISTFILE
答案4
我最后做的是HISTFILESIZE
在文件中设置为 0 .bashrc
,如下德拉夫·斯隆评论中说。
[...]
HISTFILESIZE=0
[...]