Il problema in realtà si riduce al diverso comportamento delle shell di accesso e non di accesso. Avevo impostato le variabili che controllano la cronologia nel mio ~/.bahsrc
. Questo file non viene letto quando si avvia una shell di login, viene letto solo da shell interattive non di login (da man bash
):
Quando bash viene invocato come shell di login interattiva o come shell non interattiva con
--login
opzione, prima legge ed esegue i comandi dal file/etc/profile
, se quel file esiste. Dopo aver letto quel file, cerca ~/.bash_profile,~/.bash_login
e~/.profile
, in quest'ordine, e legge ed esegue i comandi dal primo che esiste ed è leggibile. Il--noprofile
l'opzione può essere usata quando la shell viene avviata per inibire questo comportamento.[. . . ]
Quando viene avviata una shell interattiva che non è una shell di login, bash legge ed esegue i comandi da ~/.bashrc, se quel file esiste. Questo può essere inibito usando l'opzione --norc. L'opzione del file --rcfile costringerà bash a leggere ed eseguire i comandi dal file invece che da ~/.bashrc.
Pertanto, ogni volta che ho effettuato l'accesso, o sono passato a un tty o ho usato ssh, il .history
il file veniva troncato perché non l'avevo impostato sulla dimensione corretta in ~/.profile
anche. Alla fine me ne sono reso conto e ho semplicemente impostato le variabili in ~/.profile
dove appartengono, invece di ~/.bashrc
Quindi, il motivo per cui il mio ~/.history
veniva troncato perché avevo impostato solo le variabili HISTORY in un file letto da shell interattive non di accesso e quindi ogni volta che eseguivo un diverso tipo di shell le variabili venivano ignorate e il file veniva tagliato di conseguenza.
Il mio suggerimento è di utilizzare un altro file come HISTFILE
, non il ~/.bash_history
predefinito .
Anche se non ho una spiegazione analitica, cercherò di delineare ciò che mi ha portato a questo suggerimento:Se usi bash
come shell predefinita (di login) e usa anche X
(che entrambi sono molto probabili) hai un bash
in esecuzione istanza subito dopo il login (grafico):
systemd
...
|-login
| `-bash <<====
| `-slim
| |-X -nolisten tcp vt07 -auth /var/run/slim.auth
| | `-{X}
| `-fluxbox
| `-xterm -bg black -fg white
| `-bash
...
Penso che questa istanza sia una shell di login, quindi non legge il tuo ~/.bashrc
e quindi non saprà nulla del histappend
opzione:
man bash(1) :quando una shell interattiva che non è un login shell viene avviata, bash legge ed esegue i comandi da /etc/bash.bashrc e ~/.bashrc, se questi file esistono. (...)
Finché questa "shell madre" è in esecuzione, va tutto bene, ma alla sua conclusione (ad esempio, l'arresto del sistema) sovrascriverà ~/.bash_history
(perché questo è il valore predefinito) e incasina la tua cronologia o la ritaglia sull'avvio del sistema a (di nuovo predefinito) 500 righe. (O forse entrambi...)
Mi colpisce anche che non sia sufficiente includere la configurazione della cronologia in ~/.bashrc
, poiché questa non dovrebbe essere una configurazione così insolita. Non ho spiegazioni per questo.
Per quanto riguarda il tuo problema, che "le shell di accesso mostrano ancora lo stesso comportamento", puoi provare a includere la configurazione della cronologia anche in ~/.bash_profile
:
man bash(1) :Quando bash viene invocato come shell di login interattiva, o come shell non interattiva con l'opzione --login, prima legge ed esegue i comandi dal file /etc/profile, se quel file esiste. Dopo aver letto quel file, cerca ~/.bash_profile, (...)
Sfortunatamente non posso pubblicare una spiegazione più giustificata con i dettagli del mio bash
config, dato che sono un zsh
ragazzo...
Poiché tutte le tue impostazioni sono in ordine secondo la pagina man e poiché il file della cronologia non è limitato dalla dimensione (byte), l'unica spiegazione possibile a cui riesco a pensare. Ha a che fare con il modo in cui il guscio muore.
Secondo il riferimento online, la graziosa uscita (cronologia salvata) si verifica solo quando la shell riceve SIGHUP. Non riesco davvero a spiegare come il tuo sistema propaga i segnali al riavvio, ma sospetto che la tua shell si chiuda con SIGKILL o SIGPWR.
Potrebbe essere perché il tuo WM viene eseguito in modo asincrono (aspetta) e l'emulatore di terminale generato dal WM in cui bash riceve un segnale di forzatura dell'uscita diverso da SIGHUP. Potrebbe anche essere che il sistema operativo sia troppo veloce per inviare il "kill finale" a tutti i processi prima che il grazioso SIGHUP iniziale riesca ad arrivare alla shell tramite X -> WM -> xterm, forse perché X o WM impiegano più tempo per uscire rispetto a ci vuole che il sistema operativo sia pronto per andare giù.
Sono in acque profonde con questa roba, ma penso che qualcosa del genere causi il comportamento irregolare. Ho già avuto questo problema e il rimedio più solido è exit
in bash dove vuoi conservare la cronologia.
Ho notato history -a
nella tua domanda, e non riesco a pensare al motivo per cui ciò non sarebbe sufficiente per preservare la storia.
Potresti risolvere il problema scoprendo cosa uccide davvero la tua bash e passando a capire da dove ha origine il segnale e risolvere il problema lì, o semplicemente svuotare la cronologia quando sai quale segnale è l'ultimo (supponendo che i dischi siano ancora online per allora ):
trap "echo got 1 >/tmp/sig1; exit" SIGHUP
trap "echo got 2 >/tmp/sig2; exit" SIGINT
trap "echo got 15 >/tmp/sig15; exit" SIGTERM
.. and so on...
Lo screenshot incluso illustra ciò di cui sto parlando nel secondo e terzo paragrafo. La sequenza è la shell in da sinistra , uccidi il guscio sinistro da destra e cattura la storia.
man bash
All'avvio, (...) Il file denominato dal valore di HISTFILE viene troncato, se necessario, per contenere non più del numero di righe specificato dal valore di HISTFILESIZE (+ default 500).
Se l'opzione della shell histappend è abilitata (+ default qui), le righe vengono aggiunte al file della cronologia, altrimenti il file della cronologia viene sovrascritto.
riferimento online
3.7.6 Segnali
Quando Bash è interattivo, in assenza di trappole, ignora SIGTERM (in modo che "kill 0" non uccida una shell interattiva) e SIGINT viene catturato e gestito (in modo che il builtin wait sia interrompibile). Quando Bash riceve un SIGINT, interrompe qualsiasi ciclo in esecuzione. In tutti i casi, Bash ignora SIGQUIT. Se il controllo del lavoro è attivo (vedi Controllo del lavoro), Bash ignora SIGTTIN, SIGTTOU e SIGTSTP.
I comandi non incorporati avviati da Bash hanno gestori di segnale impostati sui valori ereditati dalla shell dal suo genitore. Quando il controllo del lavoro non è attivo, i comandi asincroni ignorano SIGINT e SIGQUIT oltre a questi gestori ereditati. I comandi eseguiti come risultato della sostituzione del comando ignorano i segnali di controllo del lavoro generati dalla tastiera SIGTTIN, SIGTTOU e SIGTSTP.
La shell esce per impostazione predefinita alla ricezione di un SIGHUP. Prima di uscire, una shell interattiva invia nuovamente il SIGHUP a tutti i lavori, in esecuzione o interrotti. I lavori interrotti vengono inviati SIGCONT per garantire che ricevano il SIGHUP. Per evitare che la shell invii il segnale SIGHUP a un particolare lavoro, dovrebbe essere rimosso dalla tabella dei lavori con l'integrato disown (vedi Integrazioni di controllo del lavoro) o contrassegnato per non ricevere SIGHUP usando disown -h.
Se l'opzione della shell huponexit è stata impostata con shopt (vedi The Shopt Builtin), Bash invia un SIGHUP a tutti i job quando esce una shell di login interattiva.
Se Bash sta aspettando il completamento di un comando e riceve un segnale per il quale è stata impostata una trappola, la trappola non verrà eseguita fino al completamento del comando. Quando Bash è in attesa di un comando asincrono tramite l'integrato wait, la ricezione di un segnale per il quale è stata impostata una trappola farà sì che l'integrato wait ritorni immediatamente con uno stato di uscita maggiore di 128, subito dopo che la trappola viene eseguita.
Schermata dimostrativa