突然、コマンド ライン履歴にアクセスできなくなったのはなぜですか?

突然、コマンド ライン履歴にアクセスできなくなったのはなぜですか?

私はkshUbuntu 20.04で (バージョン: sh (AT&T Research) 2020.0.0) を使用しており、vi コマンドライン編集モード ( ) を使用していますset -o vi。これは何年も問題なく動作していましたが、最近いくつかの異常に気づき、ついに今朝完全に動作しなくなりました。

  • ~/.sh_histfile今朝の時点でコマンドが保存されなくなっているのがわかります
  • 以前は、入力したすべてのコマンドは、 を使用して上にスクロールするEsckか、 を使用して検索することで見つけることができましたEsc/
  • しばらく前に、これは成功したコマンドのみを記憶するように変更されたようです (これは面倒です)。

昨日は構成に変更を加えていない(と思う)のですが、コマンド ライン履歴は root ユーザーに対して機能します。

権限は~/.sh_histfile600 で、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通常はレコードを書き込むために呼び出されますが、バグがアクティブな場合は呼び出されません。

その結果、新しいファイル記述子.sh_hisory〜のためにすべてのコマンド。これは、コメントに記載されているように、 で見たものと同じである可能性があります/proc/PID/fd。 それ以上のコマンドはファイルに書き込まれません。

少なくともここでの解決策は、古い履歴をアーカイブして新しい履歴を開始することです。シェルを再起動することをお勧めします。

定義されていない場合HISTSIZE、バグをトリガーする制限は小さく、数百レコードです。これを 50000 などの大きな数値に設定して「遅延」させることができます。私のテストでは、サイズが 50000 の約 32k 行でトリガーされました。サイズを 500000 に増やすと、再び期待どおりに動作するようになりました。

前述のとおり、ksh932020 バージョンの代わりにインストールすることをお勧めします。状況から判断すると、2020 は停止しています。( 931993 年のものという意味ではありませんが、そのバージョンに基づいています。おそらく93u)

この93uバージョンにはこのバグはありません。

もし/etc/skel/.kshrcソース化されていない場合は、そのファイルをホームディレクトリにコピーすることも必要でしょう。おそらくすでにHISTSIZEセットがある場合は、2020 リリースを続行する場合は、それを大きな値に変更します。



元の「コメント」

これはコメントとしては長すぎるので、「回答」として書きます。(Linux を想定)

何が起こっているのかの手がかりは、次の方法で見つかるかもしれません:


1 つのターミナルでksh通常どおり実行します。そのシェルの pid を取得します。

チェックしてください/proc/PID/fd/。通常は、fd 3が開いているはずです。/home/username/.sh_history

2 番目のシェルで を実行しますstrace -p PID。最初のシェルで と入力すると、k通常、 を実行しているシェルに次のような内容が表示されます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、前のコマンドが表示されます。

履歴を書く:

最初のシェルでコマンドを入力します。以下のログでは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

履歴ファイルに書き込む行です。

関連情報