¿Por qué de repente no puedo acceder a mi historial de línea de comandos?

¿Por qué de repente no puedo acceder a mi historial de línea de comandos?

Utilizo ksh(versión: sh (AT&T Research) 2020.0.0) en Ubuntu 20.04 y uso el modo de edición de línea de comandos vi ( set -o vi). Esto ha funcionado bien durante años, pero recientemente he notado algunas rarezas y finalmente esta mañana dejó de funcionar por completo.

  • Veo que los comandos ya no se guardan ~/.sh_histfilea partir de esta mañana.
  • En el pasado, todos los comandos que ingresaba se podían encontrar desplazándose hacia arriba con Escko, por ejemplo. buscando con Esc/.
  • Hace un tiempo, esto pareció cambiar y solo recordar comandos exitosos (lo cual es una molestia).

Ayer no hice ningún cambio en mi configuración (creo), pero el historial de la línea de comandos funciona para el usuario root.

Los permisos ~/.sh_histfileson 600 y HISTFILEno están configurados, ni para mi usuario normal ni para mi root.

¿Alguna idea de qué salió mal y, por supuesto, cómo solucionarlo? Lo ideal sería volver a la situación en la que todo lo que escribí en la línea de comando y terminé Enterse guardaría en ~/.sh_histfile.

Editar

Se establecen las siguientes variables:

$ 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

El perfil local contiene solo elementos predeterminados y un par de líneas al final que agregué:

$ 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

Respuesta1

Esto esNo verificadopor otras fuentes, sino simplemente una mirada al caso.

¡NÓTESE BIEN! Esto se relaciona con ksh-2020.

Hay un error en el manejo del historial cuando el historial supera un cierto tamaño (bytes). Se manifiesta en que la longitud del historial es 1 (también conocido como cero) y permanece ahí. Si uno alcanza el límite que desencadena el error mientras está en kshél, se manifestará en la próxima ejecución.

Usando algo como:

PS1='$_pwd [!]\$ '

muestra la ruta + número de entradas del historial.

En una carrera normalsh_histinitse llama al inicio. Por alguna razón, no rastreada, esta función se llamapara cada comandocuando este error está activo. Máshist_writeNormalmente se llama para escribir el registro, pero no se llama cuando el error está activo.

Como resultado uno termina conun nuevo descriptor de archivoa .sh_hisoryparacada comando. Es probable que esto sea lo que también vio /proc/PID/fden los comentarios. Otros comandos no se escriben en el archivo.

La solución, al menos aquí, es archivar la historia antigua y comenzar una nueva. Probablemente sea aconsejable reiniciar Shell.

Sin HISTSIZEdefinirlo, el límite para activar el error es pequeño. Unos cientos de registros. Puedes configurarlo en un número grande, como 50000, para "retrasarlo". En mis pruebas, se activaron alrededor de 32k líneas con un tamaño de 50000. Aumenté el tamaño a 500000 y luego funcionó como se esperaba nuevamente.

Como se señaló, también es probable que sea recomendable instalarla ksh93en lugar de la versión 2020. Por lo que parece, el 2020 se ha estancado. ( 93No significa que sea de 1993, sino que se basa en esa versión. Probablemente 93u)

La 93uversión no tiene este error.

Si /etc/skel/.kshrcno se obtiene, es probable que también desee copiar ese archivo a su directorio de inicio. ÉlprobableYa tienes un HISTSIZEconjunto, cámbialo a un valor grande si continúas con la versión 2020.



"Comentario" original

Esto es demasiado largo para un comentario, así que lo escribo como una "respuesta". (Asumiendo Linux)

Posiblemente puedas encontrar una pista de lo que está pasando:


En una terminal funciona kshnormalmente. Obtén el pid de ese caparazón.

Controlar /proc/PID/fd/. Normalmente debería tener abierto fd 3 a/home/username/.sh_history

En el segundo caparazón hazlo strace -p PID. En el primer shell, cuando ingresa, knormalmente debería ver algo como esto en el shell ejecutándose strace.

Leer la historia 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

Aquí:

read(0, "k", 80) = 1 leer desde STDIN, lee 1 byte, "k" (La clave ingresada)
read(3, "\201\1[ ... leer 65536 bytes de fd 3, lea el archivo de historial. write(2, "man foo... escribirman foo, se muestra el comando anterior.

Escribir historia:

En el primer shell ingrese un comando. En el registro a continuación entré cd ircdesde~/tmp

Extracto 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

Aquí el:
write(3, "cd irc\n\0", 8) = 8

es la línea que escribe en el archivo histórico.

información relacionada