Почему я внезапно не могу получить доступ к истории командной строки?

Почему я внезапно не могу получить доступ к истории командной строки?

Я использую ksh(версия: sh (AT&T Research) 2020.0.0) на Ubuntu 20.04 и режим редактирования командной строки 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

Этоне подтвержденодругими источниками, а лишь взглядом на дело.

NB! Это касается ksh-2020.

В обработке истории есть ошибка, когда история превышает определенный размер (байты). Она проявляется в том, что длина истории становится 1 (она же ноль) и остается на этом уровне. Если достичь предела, который вызывает ошибку, она kshпроявится при следующем запуске.

Используя что-то вроде:

PS1='$_pwd [!]\$ '

показывает путь + количество записей в истории.

В нормальном режимеsh_histinitвызывается при запуске. По какой-то причине, не отслеженной, эта функция вызываетсядля каждой командыкогда этот баг активен. Далееhist_writeобычно вызывается для записи записи, но не вызывается, когда ошибка активна.

В результате получаетсяновый файловый дескриптордля .sh_hisoryдлякаждая команда. Это, вероятно, то, что вы также видели /proc/PID/fdв комментариях. Дальнейшие команды не записываются в файл.

Решение, по крайней мере здесь, архивировать старую историю и начать новую. Вероятно, целесообразно перезапустить оболочку.

Без HISTSIZEопределения предел для срабатывания ошибки невелик. Несколько сотен записей. Вы можете установить его на большое число, например 50000, чтобы «задержать» его. В моих тестах он затем срабатывал около 32 тыс. строк размером 50000. Увеличил размер до 500000, и затем он снова заработал, как и ожидалось.

Как уже отмечалось, скорее всего, целесообразно установить ksh93версию 2020 года. Судя по всему, 2020 год застопорился. ( 93это не значит, что он с 1993 года, но на основе той версии. Скорее всего 93u)

В этой 93uверсии этой ошибки нет.

Если /etc/skel/.kshrcисходный файл отсутствует, вы, вероятно, также захотите скопировать этот файл в свой домашний каталог. Онвероятныйу вас уже есть HISTSIZEнабор, измените его на большее значение, если вы продолжите выпуск 2020 года.



Оригинальный "комментарий"

Это слишком длинно для комментария, поэтому я напишу это как «ответ». (Предполагается, что Linux)

Возможно, вы найдете подсказку о том, что происходит, если:


В одном терминале запустите kshнормально. Получите pid этой оболочки.

Проверьте /proc/PID/fd/. Обычно он должен иметь открытый fd 3 для/home/username/.sh_history

Во второй оболочке сделайте 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[ ... прочитано 65536 байт из fd 3, прочитать файл истории. 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

это строка, которая записывает в файл истории.

Связанный контент