為什麼我突然無法訪問我的命令行歷史記錄?
我
ksh
在 Ubuntu 20.04 上使用 (version: sh (AT&T Research) 2020.0.0),我使用 vi 命令行編輯模式 (set -o vi
)。這多年來一直執行良好,但最近我注意到一些奇怪的事情,最後今天早上它完全停止了工作。
- 我可以看到命令不再保存在
~/.sh_histfile
今天早上- 過去,我輸入的所有命令都可以通過向上滾動來找到,
Esc``k
例如。搜尋Esc``/
。- 不久前,這似乎變成了只記住成功的命令(這很麻煩)。
我昨天沒有對我的配置進行任何更改(我認為),但是命令行歷史記錄適用於 root 使用者。
權限
~/.sh_histfile
為 600,並且HISTFILE
未設置,無論是對於我的普通使用者還是 root。知道出了什麼問題——當然還有如何解決它?理想情況下,當我在命令行上編寫並完成的任何內容
Enter
都將保存到~/.sh_histfile
.編輯
設置以下變數:
$ set _=export COMP_CWORD=0 COMP_KEY=0 COMP_POINT=0 COMP_TYPE=0 COMP_WORDBREAKS=$'"\'@><=;|&(:' DBUS_SESSION_BUS_ADDRESS='unix:path=/run/user/1000/bus' DISPLAY=localhost:11.0 ENV=/home/jan.andersen/.kshrc FCEDIT=/usr/bin/ex HISTCMD=1 HOME=/home/jan.andersen IFS=$' \t\n' JOBMAX=0 KSH_VERSION=.sh.version LANG=en_US.UTF-8 LESS=X LINENO=1 LOGNAME=jan.andersen MAILCHECK=600 MOTD_SHOWN=pam OLDPWD=/home/jan.andersen OPTIND=1 PATH=/home/jan.andersen/.local/bin:/usr/local/glassfish5/bin:/usr/local/glassfish5/glassfish/bin:/usr/local/texlive/2019/bin/x86_64-linux:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games PPID=3887 PS1=$'\'$ \'' PS2='> ' PS3='#? ' PS4='+ ' PWD=/home/jan.andersen RANDOM=18082 SECONDS=17131.589 SHELL=/usr/bin/ksh SHLVL=1 SH_OPTIONS=astbin=/opt/ast/bin SSH_TTY=/dev/pts/1 TERM=xterm-256color TMOUT=0 USER=jan.andersen XDG_RUNTIME_DIR=/run/user/1000 XDG_SESSION_CLASS=user XDG_SESSION_ID=10 XDG_SESSION_TYPE=tty
本地配置文件僅包含預設內容和最後幾行,我已添加:
$ cat .profile # ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login # exists. # see /usr/share/doc/bash/examples/startup-files for examples. # the files are located in the bash-doc package. # the default umask is set in /etc/profile; for setting the umask # for ssh logins, install and configure the libpam-umask package. #umask 022 # if running bash if [ -n "$BASH_VERSION" ]; then # include .bashrc if it exists if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi fi # set PATH so it includes user's private bin if it exists if [ -d "$HOME/bin" ] ; then PATH="$HOME/bin:$PATH" fi # set PATH so it includes user's private bin if it exists if [ -d "$HOME/.local/bin" ] ; then PATH="$HOME/.local/bin:$PATH" fi #eval $(ssh-agent -s) #ssh-add ~/.ssh/id_rsa export SSH_AUTH_SOCK=${XDG_RUNTIME_DIR}/ssh-agent.socket
這沒有得到其他消息來源的驗證,而只是看一下案例。
注意!這與 ksh-2020 有關。
當歷史記錄超過一定大小(字節)時,處理歷史記錄會出現錯誤。它表現為歷史長度為 1(又名零)並保持在那裡。如果一個達到觸發錯誤的限制,而
ksh
它在下一次執行時就會顯現出來。使用類似的東西:
PS1='$_pwd [!]\$ '
顯示路徑 + 歷史條目數。
在正常執行
sh_histinit
中,在啟動時呼叫。由於某種原因,未追查,當此錯誤處於活動狀態時*,每個命令都會呼叫此函式。*通常呼叫進一步hist_write
來寫入記錄,但是當錯誤處於活動狀態時不會呼叫它。結果,每個命令都有一個新的文件描述符
.sh_hisory
。如評論中所述,這很可能是您也看到的。進一步的命令不會寫入文件。/proc/PID/fd
至少在這裡,解決方案是歸檔舊曆史並開始新的歷史。可能建議重新啟動 shell。
如果沒有
HISTSIZE
定義,則觸發 bug 的限制很小。幾百條記錄。您可以將其設置為一個大數字,例如 50000,以“延遲”它。在我的測試中,它觸發了大約 32k 行,大小為 50000。將大小增加到 500000,然後它再次按預期工作。如前所述,也可能建議安裝
ksh93
而不是 2020 版本。從事情的外觀來看,2020年已經停滯不前。(93
並不意味著它是從 1993 年開始的 - 而是基於那個版本。可能93u
)
93u
版本沒有這個bug 。如果
/etc/skel/.kshrc
不是來源,您可能還希望將該文件複製到您的主目錄。它可能已經有一個HISTSIZE
集合,如果您繼續使用 2020 版本,請將其更改為一個很大的值。原創“評論”
這對評論來說太長了,所以我把它寫成一個“答案”。(假設 Linux)
您可能會通過以下方式找到正在發生的事情的線索:
在一個終端中執行
ksh
正常。獲取那個 shell 的 pid。檢查
/proc/PID/fd/
。它通常應該有 open fd 3 to/home/username/.sh_history
在第二個外殼做
strace -p PID
. 在您輸入的第一個 shell中,您k
通常應該在 shell running 中看到類似的內容strace
。閱讀歷史
k
:select(1, [0], NULL, NULL, NULL) = 1 (in [0]) recvfrom(0, 0x7ffdcff6c0d0, 80, MSG_PEEK, NULL, NULL) = -1 ENOTSOCK (Socket operation on non-socket) read(0, "k", 80) = 1 lseek(3, 0, SEEK_SET) = 0 lseek(3, 0, SEEK_SET) = 0 read(3, "\201\1[ --help\n\0exit\n\0env\n\0\0ls\n\0q\n\0\0"..., 65536) = 258 lseek(3, 0, SEEK_END) = 258 write(2, "man foo\10\10\10\10\10\10\10", 14) = 14
這裡:
read(0, "k", 80) = 1
從 STDIN讀取,讀取 1 個字節,“k”(輸入的密鑰)
read(3, "\201\1[ ...
從 fd 3 讀取 65536 個字節,讀取歷史文件。write(2, "man foo...
writeman foo
,顯示上一個命令。寫歷史:
在第一個 shell 中輸入命令。在下面的日誌中,我
cd irc
從~/tmp
進入摘錄*
c<Enter>
*write(2, "c", 1) = 1 select(1, [0], NULL, NULL, NULL) = 1 (in [0]) recvfrom(0, 0x7ffdcff6c0d0, 80, MSG_PEEK, NULL, NULL) = -1 ENOTSOCK (Socket operation on non-socket) read(0, "\r", 80) = 1 ioctl(2, TCGETS, {B38400 opost -isig -icanon -echo ...}) = 0 ioctl(2, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...}) = 0 ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0 write(2, "\n", 1) = 1 lseek(3, 0, SEEK_END) = 270 lseek(3, 0, SEEK_CUR) = 270 lseek(3, 270, SEEK_SET) = 270 read(3, "", 65536) = 0 lseek(3, 0, SEEK_END) = 270 lseek(3, 0, SEEK_END) = 270 write(3, "cd irc\n\0", 8) = 8 lseek(3, 0, SEEK_CUR) = 278 chdir("irc") = 0 lseek(3, 0, SEEK_END) = 278 lseek(3, 278, SEEK_SET) = 278 lseek(3, 278, SEEK_SET) = 278 read(3, "", 65536) = 0 write(2, "~/tmp/irc [36]$ ", 16) = 16
這裡:
write(3, "cd irc\n\0", 8) = 8
是寫入歷史文件的行。