为什么 bash_history 总是出现相同的情况并且不使用非登录 shell 进行更新?

为什么 bash_history 总是出现相同的情况并且不使用非登录 shell 进行更新?

在过去的几天里,我注意到每当我关闭系统(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/nullln -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)。

不清楚的一件事是HISTFILEshell 何时检查。例如,如果在 中设置.bash_profile,我不确定它是否会影响 shell 历史记录的读取,因为它是在 shell 启动之后,但在向用户提供第一个命令提示符之前。

答案3

您只需取消设置$HISTFILE(其中包含历史文件的路径),这不会影响您在当前会话中使用历史记录的能力:

unset HISTFILE

答案4

我最后做的是HISTFILESIZE在文件中设置为 0 .bashrc,如下德拉夫·斯隆评论中说。

[...]
HISTFILESIZE=0
[...]

相关内容