Cronologia BASH troncata a 500 righe per ogni accesso


22

Per qualche motivo, non riesco a far sì che il mio sistema mantenga la mia cronologia BASH dopo un riavvio. Ecco le sezioni rilevanti del mio ~/.bashrc:

shopt -s histappend
PROMPT_COMMAND='history -a; updateWindowTitle'
export HISTCONTROL=ignoredups
export HISTSIZE=9999
export HISTFILESIZE=999999
export HISTFILE="$HOME/.bash_history"

Per quanto ne so, queste sono tutte le opzioni necessarie ( so di essere stata in grado di conservare la cronologia attraverso più riavvii senza tutte queste in passato). Tuttavia, nonostante abbia aggiunto queste opzioni diversi riavvii, dopo un riavvio perdo ancora gran parte della mia storia. Non è vuoto, ma non ha le 9999 righe che avevo prima di riavviare.

Prima che qualcuno si lamenti, sì, ho letto queste domande. Ho implementato alcuni dei loro suggerimenti come elencato sopra, il resto era inutile o non pertinente:

Se non ci sono altri comandi pertinenti lì dentro, puoi vedere il mio intero ~/.bashrc qui .

Quindi, cosa mi sto perdendo? Perché la mia cronologia non è stata salvata? Se qualcuno pensa che un altro file possa essere pertinente, fammelo sapere e lo posterò. Ho controllato eseguendo grep -i hist \.*nel mio $HOMEche ha mostrato che l'unico .file rilevante contenente la stringa histo HISTera .bashrc.

Sto usando Linux Mint Debian Edition, GNU bash, versione 4.2.36 (1) -release (x86_64-pc-linux-gnu) e il mio emulatore di terminale preferito (nel caso sia rilevante) è terminator.


AGGIORNARE:

Seguendo il suggerimento di @ mpy nei commenti, ho cambiato il mio ~/.bashrcin HISTFILE=~/bash_historycontrapposto al default ~/.bash_historye questo sembra risolvere il problema per le shell interattive . Le shell di accesso mostrano ancora lo stesso comportamento, con la cronologia troncata a 500righe. Tuttavia, non ci sono HISTvariabili correlate impostate nei file pertinenti:

$ for f in /etc/profile ~/.profile ~/.bash_profile ~/.bash_login; do \
   echo -ne "$f :"; echo `grep HIST $f`; \
done
/etc/profile :
/home/terdon/.profile :grep: /home/terdon/.profile: No such file or directory
/home/terdon/.bash_profile :grep: /home/terdon/.bash_profile: No such file or directory
/home/terdon/.bash_login :grep: /home/terdon/.bash_login: No such file or directory
$ grep -r HIST /etc/profile.d/  <-- returns nothing

Quindi, perché l'impostazione HISTSIZEe HISTFILESIZEnel ~/.bashrcnon basta a meno che non abbia impostato esplicitamente $HISTFILEqualcosa di diverso da quello predefinito ~/.bash_history?


Sei il proprietario di .bash_history o root? Fai ls -l .bash_history
Adnan Bhatti il

1
@MSStp sì, è di mia proprietà. Grazie per il suggerimento, ma non vedo come potrebbe essere un problema di autorizzazioni, o ho accesso in lettura / scrittura ad esso o no. Dato che un po 'di storia viene salvata, lo faccio chiaramente. Se bash avesse un'impostazione che causava problemi quando questo file non era di proprietà dell'utente, si lamentava o l'intera funzionalità della cronologia non funzionava.
terdon,

quando esegui il historycomando, l'output che vedi è identico a quello che vedi, in esecuzione cat .bash_history, diverso dai numeri di riga? Intendo il historycomando elenca i timestamp o altre informazioni? Il motivo per cui ti sto chiedendo è che, se vedi queste cose esoteriche, significa che c'è un altro modulo / funzione / programma, che sta facendo confusione con la cronologia della shell e una versione errata o errata di qualunque cosa sia, potrebbe causarti il ​​dolore .
MelBurslan

@Mel_Burslan sì, è lo stesso, l'unica differenza sono i numeri di riga.
terdon,

2
Ok, un suggerimento un po 'strano, ma è anche un problema noioso ;): prova un altro file come HISTFILE, non quello predefinito ~/.bash_history. Spiegazione molto costruita: suppongo che bash sia la shell predefinita, quindi all'avvio del sistema una shell non interattiva è il genitore della sessione X (suppongo anche che tu usi X), che non saprà nulla sull'opzione histappend (poiché solo .bashrc letto da shell interattive), quindi finché questa shell genitore esegue tutto va bene, ma al termine (cioè arresto del sistema) sovrascriverà ~/.bash_history(che è l'impostazione predefinita) e
rovina

Risposte:


17

Il problema si riduce in realtà al diverso comportamento delle shell di accesso e non di accesso. Avevo impostato le variabili che controllano la storia nel mio ~/.bahsrc. Questo file non viene letto all'avvio di una shell di accesso, viene letto solo da shell interattive non di accesso (da man bash):

Quando bash viene invocato come shell di login interattiva o come shell non interattiva con l' --loginopzione, legge innanzitutto ed esegue i comandi dal file /etc/profile, se quel file esiste. Dopo aver letto quel file, cerca ~ / .bash_profile, ~/.bash_logine ~/.profile, in quell'ordine, legge ed esegue i comandi dal primo che esiste ed è leggibile. L' --noprofileopzione può essere utilizzata all'avvio della shell per inibire questo comportamento.

[. . . ]

Quando viene avviata una shell interattiva che non è una shell di accesso, bash legge ed esegue i comandi da ~ / .bashrc, se quel file esiste. Questo può essere inibito usando l'opzione --norc. L'opzione --rcfile forzerà bash a leggere ed eseguire comandi dal file anziché ~ / .bashrc.

Pertanto, ogni volta che eseguivo l'accesso o scendevo su un tty o utilizzavo ssh, il .historyfile veniva troncato perché non avevo impostato la dimensione ~/.profilecorretta. Alla fine me ne sono reso conto e ho semplicemente impostato le variabili a ~/.profile cui appartengono , anziché~/.bashrc

Quindi, il motivo per cui mi ~/.historystavo troncando era perché avevo impostato le variabili HISTORY in un file letto solo da shell interattive e non di login e quindi ogni volta che eseguivo un diverso tipo di shell le variabili venivano ignorate e il file veniva tagliato di conseguenza.


Ottimo punto, grazie per averlo condiviso! Tuttavia, non sono d'accordo: questo file non viene letto all'avvio di una shell di accesso, ma viene letto solo da shell interattive. Perché anche una shell di accesso può essere interattiva. Altrimenti l'intero meccanismo della storia non avrebbe senso. IMHO .bashrcnon viene letto da (shell di login OR non interattive).
mpy

@mpy In effetti, mi spiace, intendevo shell interattive senza accesso. Risposta modificata.
terdon,

1
@terdon, il linguaggio comune è che le opzioni di shell interattive non vanno in ~ / .profile o ~ / .bash_profile. Le opzioni interattive della shell sono inserite in ~ / .bashrc. Per evitare di dover mantenere le impostazioni in due punti, i seguenti comandi possono essere inseriti nella parte superiore di un ~ / .bash_profile: export BASH_ENV=~/.bashrc ; if [ -f ~/.bashrc ]; then . ~/.bashrc; fi... e nella parte superiore di ~ / .bashrc mettere un segno di spunta per assicurarsi che si stia davvero eseguendo in modo interattivo: [ -z "$PS1" ] && return... Certo, è solo un idioma.
Noah Spurrier,

1
@NoahSpurrier BASH_ENVnon è rilevante, riguarda solo shell non interattive. Per quanto riguarda il "linguaggio", è qualcosa che Debian ha iniziato e con cui personalmente non sono d'accordo. Ho spesso opzioni grafiche ( xsete simili) nel mio .bashrc e non voglio quelle attive quando eseguo shell di login da un tty o attraverso ssh. Io voglio che il mio .profile e .bashrc separati. Molti (anche se non tutti) i gestori degli accessi generano .profile quando si accede in modo che le variabili globali siano meglio impostate lì dove saranno lette solo una volta e non ogni volta che si apre un terminale.
terdon,

1
@WilsonF sì. I file vengono letti in sequenza e i file personali ( ~/.profileo ~/.bashrc) vengono letti per ultimi. Qualsiasi cosa impostata in queste avrà la precedenza sulle impostazioni globali. Hai perfettamente ragione, non dovresti impostare queste variabili /etc/bash.bashrc. Utilizzare ~/.profile(o ~/.bash_profile) invece.
terdon,

11

Il mio consiglio è di usare un altro file come HISTFILE, non quello predefinito ~/.bash_history.

Anche se non ho una spiegazione analitica, proverò a delineare ciò che mi ha portato a questo suggerimento: se usi bashcome shell (login) predefinita e usi anche X(che è molto probabile) hai bashun'istanza in esecuzione subito dopo il (grafico ) accesso:

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 la tua ~/.bashrce quindi non sa nulla histappenddell'opzione:

man bash (1) : Quando viene avviata una shell interattiva che non è una shell di accesso , bash legge ed esegue i comandi da /etc/bash.bashrc e ~ / .bashrc, se questi file esistono. (...)

Fintanto che questa "shell genitore" funziona, tutto va bene, ma alla sua fine (cioè arresto del sistema) sovrascriverà ~/.bash_history(perché è il valore predefinito) e rovina la cronologia o le clip sul sistema iniziano a (di nuovo impostazione predefinita) 500 Linee. (O forse entrambi ...)

Mi colpisce anche il fatto che non sia sufficiente includere la configurazione della cronologia ~/.bashrc, poiché non dovrebbe essere un'installazione così rara. 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, legge prima ed esegue i comandi dal file / etc / profile, se quel file esiste. Dopo aver letto quel file, cerca ~ / .bash_profile, (...)

Purtroppo non posso pubblicare una spiegazione più giustificata con i dettagli della mia bashconfigurazione, dato che sono un zshragazzo ...


2
L'impostazione esplicita delle opzioni di cronologia nel mio ha ~/.bash_profilerisolto il problema. Ora sto usando ~/.bash_historyil mio file di cronologia ma ho semplicemente aggiunto tutte le righe da quelle ~/.bashrcmostrate nella mia domanda a ~/.bash_profile. Ancora non sono sicuro di chi stia rovinando le shell interattive, ma sembra funzionare ora, grazie!
terdon,

1
Mi dispiace non accettare, ma ho dimenticato di inviare una risposta che spiega cosa stava succedendo. L'ho capito con un po 'di aiuto da @Gilles qualche tempo fa e alla fine ho iniziato a pubblicare una risposta. Volevo accettare il mio perché in realtà spiega il problema invece di offrire una (molto buona) soluzione alternativa e potrebbe aiutare i futuri visitatori.
terdon

2

Poiché tutte le impostazioni sono in ordine in base alla pagina man e poiché il file della cronologia non è limitato dalla dimensione (byte), l'unica possibile spiegazione che mi viene in mente. Ha a che fare con il modo in cui muore il guscio.

Secondo il riferimento online, l'uscita graziosa (cronologia salvata) si verifica solo quando la shell riceve SIGHUP. Non riesco davvero a spiegare come il tuo sistema propaga i segnali quando viene riavviato, ma sospetto che la tua shell si chiuda con SIGKILL o SIGPWR.

Potrebbe essere perché il tuo WM viene eseguito in modo asincrono (attendi) e l'emulatore di terminale generato dal WM in cui bash riceve un segnale di forzatura di uscita diverso da SIGHUP. Potrebbe anche essere che il sistema operativo invii rapidamente il "kill finale" a tutti i processi prima che il grazioso SIGHUP iniziale riesca ad accedere alla shell tramite X -> WM -> xterm, probabilmente perché X o WM impiegano più tempo per uscire rispetto a ci vuole che il sistema operativo sia pronto per andare giù.

Sono su acque profonde con questa roba, ma penso che qualcosa del genere causi un comportamento irregolare. Ho già avuto questo problema in precedenza e il rimedio più solido è exitin bash dove vuoi conservare la storia.

Ho notato history -anella tua domanda e non riesco a pensare al perché 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 proviene il segnale e risolvendo il problema lì, o semplicemente svuotare la cronologia quando sai quale segnale è l'ultimo (supponendo che i dischi siano ancora online a quel punto ):

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 in cui mi trovo mi lancia da sinistra , uccido la shell sinistra da destra e seguo la storia.

uomo bash

All'avvio, (...) Il file indicato 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 shell histappend è abilitata (+ impostazione predefinita 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 l'attesa di attesa sia interrompibile). Quando Bash riceve un SIGINT, esce da qualsiasi ciclo di esecuzione. In tutti i casi, Bash ignora SIGQUIT. Se il controllo lavoro è attivo (vedere Controllo lavoro), Bash ignora SIGTTIN, SIGTTOU e SIGTSTP.

I comandi non integrati avviati da Bash hanno gestori di segnali impostati sui valori ereditati dalla shell dal suo genitore. Quando il controllo dei lavori non è attivo, i comandi asincroni ignorano SIGINT e SIGQUIT oltre a questi gestori ereditati. I comandi eseguiti a seguito della sostituzione dei comandi ignorano i segnali di controllo lavoro generati dalla tastiera SIGTTIN, SIGTTOU e SIGTSTP.

La shell esce di default al ricevimento di un SIGHUP. Prima di uscire, una shell interattiva rinvia SIGHUP a tutti i lavori, in esecuzione o arrestati. I lavori interrotti vengono inviati a SIGCONT per garantire che ricevano il SIGHUP. Per impedire alla shell di inviare il segnale SIGHUP a un particolare lavoro, è necessario rimuoverlo dalla tabella dei lavori con la funzione incorporata disconnessa (consultare la pagina relativa ai Controlli dei lavori) o contrassegnata 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 lavori quando esce una shell di login interattiva.

Se Bash è in attesa del completamento di un comando e riceve un segnale per il quale è stata impostata una trap, la trap non verrà eseguita fino al completamento del comando. Quando Bash è in attesa di un comando asincrono tramite l'attesa incorporata, la ricezione di un segnale per il quale è stata impostata una trap farà sì che l'attesa incorporata ritorni immediatamente con uno stato di uscita maggiore di 128, immediatamente dopo il quale viene eseguita la trap.

schermata dimostrativa

segnali


Non capisco davvero cosa stai facendo in quello screenshot. Che /tmp/psocosa stai uccidendo? Vedo il tuo punto sui diversi segnali di uccisione (anche se come dici tu, ho pensato che è quello che history -ac'è da affrontare). Lo proverò per un po 'e riporterò indietro.
terdon,

$ cat tmp / ps * \ n ps -o pid = | head -n1> ~ / tmp / pso \ n 17201 \ n
Ярослав Рахматуллин

0

Controlla / etc / profile e /etc/profile.d/*

Forse c'è qualcosa che non va nelle impostazioni della cronologia lì.


Grazie, ma grep -r HIST /etc/profile.d/non restituisce nulla e ho già verificato /etc/profile.
terdon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.