我在 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。将大小增加到 500000,然后它再次按预期工作。
如前所述,也可能建议安装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
是写入历史文件的行。