Por que de repente não consigo acessar meu histórico de linha de comando?

Por que de repente não consigo acessar meu histórico de linha de comando?

Eu uso ksh(versão: sh (AT&T Research) 2020.0.0) no Ubuntu 20.04 e uso o modo de edição de linha de comando vi ( set -o vi). Isso funcionou bem durante anos, mas recentemente notei algumas estranhezas e, finalmente, esta manhã parou de funcionar completamente.

  • Vejo que os comandos não estão mais sendo salvos ~/.sh_histfilea partir desta manhã
  • No passado, todos os comandos que eu digitava podiam ser encontrados rolando para cima com Esckou, por exemplo. pesquisando com Esc/.
  • Há algum tempo, isso parecia mudar para apenas lembrar comandos bem-sucedidos (o que é um incômodo).

Não fiz nenhuma alteração na minha configuração ontem (eu acho), mas o histórico da linha de comando funciona para o usuário root.

As permissões ativadas ~/.sh_histfilesão 600 e HISTFILEnão estão definidas para meu usuário normal ou root.

Alguma ideia do que deu errado - e, claro, como consertar? Idealmente, quero voltar à situação em que qualquer coisa que escrevi na linha de comando e terminei Enterseria salva em ~/.sh_histfile.

Editar

As seguintes variáveis ​​são definidas:

$ 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

O perfil local contém apenas coisas padrão e algumas linhas no final, que adicionei:

$ 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

Responder1

Isso énão verificadopor outras fontes, mas apenas uma olhada no caso.

Atenção! Isso está relacionado ao ksh-2020.

Há um erro no tratamento do histórico quando o histórico ultrapassa um determinado tamanho (bytes). Ele se manifesta no fato de que o comprimento do histórico é 1 (também conhecido como zero) e permanece lá. Se alguém atingir o limite que aciona o bug enquanto estiver nele, kshele se manifestará na próxima execução.

Usando algo como:

PS1='$_pwd [!]\$ '

mostra o caminho + número de entradas do histórico.

Em uma corrida normalsh_histinité chamado no início. Por alguma razão, não rastreada, esta função é chamadapara cada comandoquando este bug está ativo. Avançarhist_writenormalmente é chamado para escrever o registro, mas não é chamado quando o bug está ativo.

Como resultado acaba-se comum novo descritor de arquivopara .sh_hisoryparacada comando. Provavelmente é isso que você também viu /proc/PID/fdconforme observado nos comentários. Outros comandos não são gravados no arquivo.

A solução, pelo menos aqui, é arquivar a história antiga e começar uma nova. Provavelmente aconselhável reiniciar o shell.

Sem HISTSIZEdefinido, o limite para acionamento do bug é pequeno. Algumas centenas de registros. Você pode configurá-lo para um número grande, como 50.000, para "atrasá-lo". Em meus testes, ele foi acionado em torno de 32 mil linhas com tamanho de 50.000. Aumentei o tamanho para 500.000 e funcionou conforme o esperado novamente.

Conforme observado, provavelmente também é aconselhável instalar ksh93em vez da versão 2020. Ao que parece, 2020 estagnou. ( 93não significa que seja de 1993 - mas baseado nessa versão. Provavelmente 93u)

A 93uversão não possui esse bug.

Se /etc/skel/.kshrcnão for originado, você provavelmente também deseja copiar esse arquivo para o seu diretório inicial. Istoprováveljá tem um HISTSIZEconjunto, altere-o para um valor grande se continuar com a versão 2020.



"Comentário" original

É muito longo para um comentário, então escrevo como uma "resposta". (Assumindo Linux)

Você poderia encontrar uma pista sobre o que está acontecendo:


Em um terminal execute kshnormalmente. Obtenha o pid desse shell.

Verificar /proc/PID/fd/. Normalmente deveria ter aberto fd 3 para/home/username/.sh_history

No segundo shell, faça strace -p PID. No primeiro shell, quando você entra, knormalmente verá algo assim no shell em execução strace.

Leia a história por 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

Aqui:

read(0, "k", 80) = 1 leia do STDIN, leia 1 byte, "k" (a chave inserida)
read(3, "\201\1[ ... leia 65536 bytes de fd 3, leia o arquivo de histórico. write(2, "man foo... escreverman foo, o comando anterior é mostrado.

Escreva a história:

No primeiro shell, digite um comando. No log abaixo entrei cd ircde~/tmp

Trecho deentrandoc<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

Aqui o:
write(3, "cd irc\n\0", 8) = 8

é a linha que grava no arquivo de histórico.

informação relacionada