Historial de Bash: "ignorar" y "borrar" configurando conflictos con el historial común en las sesiones

85

En primer lugar, este no es un duplicado de ningún subproceso existente en SE. He leído estos dos hilos ( , ) sobre un mejor historial de bash, pero ninguna de las respuestas funciona - Por cierto, estoy en Fedora 15.

.bashrcAgregué lo siguiente al archivo en el directorio de usuarios (/ home / aahan /), y no funciona. Alguien tiene una pista?

HISTCONTROL=ignoredups:erasedups  # no duplicate entries
HISTSIZE=1000                     # custom history size
HISTFILESIZE=100000                 # custom history file size
shopt -s histappend                      # append to history, don't overwrite it
PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"  # Save and reload the history after each command finishes

Bien, esto es lo que quiero con el historial de bash (prioridad):

  • no almacene duplicados, borre los existentes
  • compartir inmediatamente el historial con todas las terminales abiertas
  • siempre agregue el historial, no lo sobrescriba
  • almacenar comandos de varias líneas como un solo comando (que está desactivado de manera predeterminada)
  • ¿Cuál es el tamaño predeterminado del historial y el tamaño del archivo histórico?
soy yo
fuente
¡bache! ¿nadie? Nada funciona. ¿Podría ser esto un problema con Fedora 15 (con Gnome 3 y ejecutándose en una máquina virtual host de Windows)?
its_me
Por favor, no "golpee" las publicaciones aquí. Si no reciben respuesta, debe preguntar con más claridad, incluir los fragmentos correctos de claves de contexto, o algo así. Si necesita atención en sus publicaciones, puede emitir recompensas que ayuden a que más personas les presten más atención.
Caleb
1
¿Estás seguro de que incluso estás usando bash? ( echo $SHELL) ¿Funcionan los ajustes si los ejecuta manualmente desde su shell abierto? Obviamente, dado que funcionan para muchos otros, la configuración es correcta, simplemente los está implementando incorrectamente. Y no Fedora15 / Gnome3 / ser una máquina virtual tiene poco que ver con la función real de bash.
Caleb
@Caleb, primero lamento haber topado la publicación. Además, hice todo lo posible para ser muy claro. No, no los he emitido en el caparazón. Acabo de copiarlos y pegarlos en el .bashrcarchivo. ¿Es eso incorrecto? ¿Puedes agregar una "respuesta" a esta publicación con los comandos de shell reales? (por favor, tenga con mi noob-dad.)
its_me
1
Todo lo que escribes en scripts o .bashrcSON comandos de shell reales. Las secuencias de comandos son solo series de comandos de shell. Además, la edición que realizó recientemente al eliminar el exportbit fue una mala idea, que debe mantenerse.
Caleb

Respuestas:

120

Este es realmente un comportamiento realmente interesante y confieso que he subestimado enormemente la pregunta al principio. Pero primero los hechos:

1. Lo que funciona

La funcionalidad se puede lograr de varias maneras, aunque cada una funciona un poco diferente. Tenga en cuenta que, en cada caso, para que el historial se "transfiera" a otro terminal (actualizado), uno tiene que presionar Enteren el terminal, donde desea recuperar el historial.

  • Opción 1:

    shopt -s histappend
    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"

    Esto tiene dos inconvenientes:

    1. Al iniciar sesión (abrir un terminal), el último comando del archivo de historial se lee dos veces en el búfer de historial del terminal actual;
    2. Las memorias intermedias de diferentes terminales no permanecen sincronizadas con el archivo de historial.
  • opcion 2:

    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

    (Sí, no es necesario shopt -s histappendy sí, tiene que estar history -c en el medio de PROMPT_COMMAND) Esta versión también tiene dos inconvenientes importantes:

    1. El archivo de historial debe ser inicializado. Tiene que contener al menos una línea no vacía (puede ser cualquier cosa).
    2. El historycomando puede dar resultados falsos, ver más abajo.

[Editar] "Y el ganador es ..."

  • opción 3:

    HISTCONTROL=ignoredups:erasedups
    shopt -s histappend
    PROMPT_COMMAND="history -n; history -w; history -c; history -r; $PROMPT_COMMAND"

    Esto es lo más lejos que puede llegar. Es la única opción para tener ambos erasedupsy el historial común trabajando simultáneamente. Esta es probablemente la solución final a todos sus problemas, Aahan.


2. ¿Por qué la opción 2 no parece funcionar (o: lo que realmente no funciona como se espera)?

Como mencioné, cada una de las soluciones anteriores funciona de manera diferente. Pero la interpretación más engañosa de cómo funciona la configuración proviene del análisis de la salida del historycomando . En muchos casos, el comando puede dar resultados falsos . ¿Por qué? Porque se ejecuta antes de la secuencia de otros historycomandos contenidos en PROMPT_COMMAND! Sin embargo, cuando se usa la segunda o tercera opción, uno puede monitorear los cambios de .bash_historycontenido (usando, watch -n1 "tail -n20 .bash_history"por ejemplo) y ver cuál es el historial real.

3. ¿Por qué la opción 3 es tan complicada?

Todo radica en la forma en que erasedupsfunciona. Como dice el manual de bash, "(...) erasedupshace que todas las líneas anteriores que coincidan con la línea actual se eliminen de la lista del historial antes de que esa línea se guarde" . Entonces, esto es realmente lo que quería el OP (y no solo, como pensaba anteriormente, que no aparezcan duplicados en secuencia ) . He aquí por qué cada uno de los history -.comandos tiene o no puede estar en PROMPT_COMMAND:

  • history -n tiene que estar allí antes history -wpara leer .bash_historylos comandos guardados desde cualquier otra terminal,

  • history -w tiene que estar allí para guardar el historial en un archivo y borrar duplicados,

  • history -a no debe colocarse allí en lugar de history -w, ya que no activa el borrado de duplicados,

  • history -ctambién es necesario porque evita destruir el búfer de historial después de cada comando,

  • y finalmente, history -res necesario para restaurar el búfer de historial desde el archivo, por lo que finalmente se comparte el historial entre las sesiones de terminal.

rozcietrzewiacz
fuente
2
+1 para "Pero la interpretación más engañosa de cómo funciona la configuración proviene del análisis de la salida del comando de historial". Creo que este es el núcleo del problema del OP. Excelente deducción.
jasonwryan
2
Finalmente vi tu punto. Por 'duplicados' querías decir algo más que yo. Solo me enfoqué en las secuencias del mismo comando . Actualicé mi respuesta - ver "opción 3". Además, para su caso, para probar cómo funciona el historial, debe usarlo en watch "tail -n 20 .bash_history"lugar de tail -f .bash_history.
rozcietrzewiacz
2
La opción 3 acaba de borrar todas mis 100,000 líneas de historia :( (bash 3.2.25 (1) -release)
Felipe Alvarez
2
history -ctambién es necesario porque evita destruir el búfer de historial después de cada comando ¿Por qué ocurre esta eliminación?
Piotr Dobrogost
2
Su solución 3 en realidad no funciona. Es extremadamente defectuoso y depende del orden en que los usuarios presionan enter en diferentes terminales. A menudo resultará en comandos perdidos, especialmente cuando se cambia de un terminal a otro. Fuente: lo probé.
6cef
8

En su comando rápido, está utilizando el -cinterruptor. De man bash:

-c   Borrar la lista del historial eliminando todas las entradas

Para compartir su historial con todos los terminales abiertos, puede usar -n:

-n   Lee las líneas del historial que aún no se han leído del archivo del historial en la lista del historial actual. Estas son líneas agregadas al archivo de historial desde el comienzo de la sesión de bash actual.

El tamaño predeterminado también está en el manual:

HISTSIZE El número de comandos para recordar en el historial de comandos (ver HISTORIAL a continuación). El valor predeterminado es 500.

Para guardar comandos de varias líneas:

La opción de shell cmdhist , si está habilitada, hace que el shell intente guardar cada línea de un comando de varias líneas en la misma entrada del historial, agregando punto y coma cuando sea necesario para preservar la corrección sintáctica. La opción de shell de Lithist hace que el shell guarde el comando con líneas nuevas incrustadas en lugar de punto y coma.

Además, no debe anteponer los comandos HIST * con export: son variables solo bash, no variables ambientales: HISTCONTROL=ignoredups:erasedupses suficiente.

jasonwryan
fuente
Entonces, esto export PROMPT_COMMAND="history -a; history -n; history -r; $PROMPT_COMMAND"es correcto? Además, ¿sabes cómo puedo hacer que el archivo de historial almacene comandos de varias líneas como un solo comando (que está desactivado de forma predeterminada)?
es_me
1
Si. Según la página del manual citada anteriormente, shopt -s cmdhistguardará varias líneas.
jasonwryan
Está bien, los probé todos. Parece que HISTCONTROL=ignoredups:erasedupsno funciona. También intenté tener eso en el .bashrcarchivo (entre las funciones personalizadas). ¿Alguna idea de lo que podría estar mal? Estoy usando Fedora 15 en una máquina virtual - - Windows 7 host.
es_me
Asegúrese de que no haya nada en los otros archivos de inicio, como /etc/bashrc, .bash_profileetc. , que lo anule.
jasonwryan
No veo ningún problema con el .bash_profilearchivo. En cuanto al contenido /etc/bashrcque lo puse aquí, eche un vistazo - pastebin.com/Uae6sE6s
its_me
8

Esto es lo que se me ocurrió y estoy feliz con eso hasta ahora ...

alias hfix='history -n && history | sort -k2 -k1nr | uniq -f1 | sort -n | cut -c8- > ~/.tmp$$ && history -c && history -r ~/.tmp$$ && history -w && rm ~/.tmp$$'  
HISTCONTROL=ignorespace  
shopt -s histappend  
shopt -s extglob  
HISTSIZE=1000  
HISTFILESIZE=2000  
export HISTIGNORE="!(+(*\ *))"  
PROMPT_COMMAND="hfix; $PROMPT_COMMAND" 

NOTAS

  • Sí, es complicado ... ¡pero elimina todos los duplicados y aún conserva la cronología dentro de cada terminal!
  • Mi HISTIGNOREignora todos los comandos que no tienen argumentos. Esto puede no ser deseable para algunas personas y puede omitirse.
usuario41176
fuente
1

Use esto en su lugar:

HISTCONTROL=ignoreboth
verndog
fuente
0

No funciona porque te olvidas de:

 -n   read all history lines not already read from the history file
      and append them to the history list

Pero parece history -nque solo tiene errores cuando export HISTCONTROL=ignoreboth:erasedupsestá en vigor.

Vamos a experimentar:

$ PROMPT_COMMAND=
$ export HISTCONTROL=ignoreboth:erasedups
$ export HISTFILE=~/.bash_myhistory
$ HISTIGNORE='history:history -w'
$ history -c
$ history -w

Aquí activamos la eliminación de duplicados, cambiamos el historial al archivo personalizado y borramos el historial. Después de completar todos los comandos, tenemos un archivo de historial vacío y un comando en el historial actual.

$ history
$ cat ~/.bash_myhistory
$ history
$ 1  [2019-06-17 14:57:19] cat ~/.bash_myhistory

Abra la segunda terminal y ejecute esos seis comandos también. Después de esto:

$ echo "X"
$ echo "Y"
$ history -w
$ history
  1  [2019-06-17 15:00:21] echo "X"
  2  [2019-06-17 15:00:23] echo "Y"

Ahora su historial actual tiene dos comandos y el archivo de historial tiene:

#1560772821
echo "X"
#1560772823
echo "Y"

Volver a la primera terminal:

$ history -n
$ history
1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
2  [2019-06-17 15:03:12] history -n

Huh ... ninguno de los echocomandos se leen. Cambie a la segunda terminal nuevamente y:

$ echo "Z"
$ history -w

Ahora el archivo de historial es:

#1560772821
echo "X"
#1560772823
echo "Y"
#1560773057
echo "Z"

Cambie a la primera terminal nuevamente:

$ history -n
$ history
  1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
  2  [2019-06-17 15:03:12] history -n
echo "Z"

Puede ver que el echo "Z"comando se fusionó con history -n.

Otro error se debe a que los comandos se leen del historial por número de comando y no por tiempo de comando, creo. Espero que otros echocomandos aparecieron en la historia

Eugen Konkov
fuente
0

erasedups no recorta (como chomp en algunos idiomas) los espacios iniciales y finales. Esto es un error Además, borrado no elimina todas las entradas anteriores.

Sajith Nallithodi
fuente