我在 Ubuntu 20.04 上使用ksh
(版本:sh (AT&T Research) 2020.0.0),並且使用 vi 命令列編輯模式(set -o vi
)。這多年來一直運作良好,但最近我注意到一些奇怪的地方,最後今天早上它完全停止工作了。
~/.sh_histfile
我可以看到從今天早上起命令不再保存在- 過去,我輸入的所有命令都可以透過使用Esck或向上滾動來找到,例如。搜尋與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
答案1
這是未經審核的透過其他來源,但只是看看這個案例。
注意!這與 ksh-2020 有關。
當歷史記錄超過一定大小(位元組)時,歷史記錄的處理會出現錯誤。它表現為歷史長度為 1(也稱為零)並保持在那裡。如果達到觸發錯誤的限制,則ksh
在下次執行時會顯現出來。
使用類似的東西:
PS1='$_pwd [!]\$ '
顯示路徑+歷史條目數。
正常運作時sh_histinit
在啟動時調用。由於某種原因,沒有追蹤到,這個函數被調用對於每個命令當這個錯誤活躍時。更遠hist_write
通常會呼叫它來寫入記錄,但當 bug 處於活動狀態時不會呼叫此函數。
結果是一個新的檔案描述符.sh_hisory
為了每個命令。這可能是您/proc/PID/fd
在評論中所看到的。進一步的命令不會寫入檔案。
至少在這裡,解決方案是歸檔舊曆史並開始新歷史。可能建議重新啟動 shell。
如果沒有HISTSIZE
定義,觸發錯誤的限制很小。幾百筆記錄。您可以將其設定為一個很大的數字,例如 50000,以「延遲」它。在我的測試中,它被觸發了大約 32k 行,大小為 50000。
如前所述,也可能建議安裝ksh93
而不是 2020 版本。從表面上看,2020年已經停滯了。 (93
並不意味著它是 1993 年的 - 而是基於該版本。可能93u
)
該93u
版本沒有這個bug。
如果/etc/skel/.kshrc
沒有來源,您可能還想將該檔案複製到您的主目錄。它可能已經有一套HISTSIZE
,如果您繼續使用 2020 版本,請將其變更為一個大值。
原創“評論”
對於評論來說太長了,所以我將其寫為“答案”。 (假設是Linux)
您可能會透過以下方式找到正在發生的事情的線索:
在一台終端運作ksh
正常。取得該 shell 的 pid。
查看/proc/PID/fd/
。它通常應該打開 fd 3 來/home/username/.sh_history
在第二個外殼中執行strace -p PID
.在第一個 shell 中,當您進入時,k
您通常應該在 shell 中看到類似這樣的內容正在運行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...
寫man 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
是寫入歷史文件的行。