it-swarm.it

Cronologia di Bash: "ignoredups" e "erasedups" creano conflitti con la cronologia comune tra le sessioni

Prima di tutto, questo non è un duplicato di alcun thread esistente su SE. Ho letto questi due thread ( 1 ° , 2 ° ) su una migliore storia bash, ma nessuna delle risposte funziona - - Sono comunque su Fedora 15.

Ho aggiunto quanto segue a .bashrc nella directory utente (/ home/aahan /) e non funziona. Qualcuno ha un indizio?

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

Va bene questo è quello che voglio con la storia di bash (priorità):

  • non memorizzare duplicati, cancellare quelli esistenti
  • condividere immediatamente la cronologia con tutti i terminali aperti
  • aggiungi sempre la cronologia, non sovrascriverla
  • memorizza i comandi multilinea come un singolo comando (disattivato per impostazione predefinita)
  • qual è la dimensione della cronologia predefinita e la dimensione del file della cronologia?
92
its_me

Questo è in realtà un comportamento davvero interessante e confesso di aver ampiamente sottovalutato la domanda all'inizio. Ma prima i fatti:

1. Cosa funziona

La funzionalità può essere ottenuta in diversi modi, sebbene ciascuno funzioni in modo leggermente diverso. Si noti che, in ogni caso, per far "trasferire" la cronologia su un altro terminale (aggiornato), è necessario premere Enter nel terminal, dove vuole recuperare la storia.

  • opzione 1:

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

    Ciò ha due inconvenienti:

    1. All'accesso (apertura di un terminale), l'ultimo comando dal file della cronologia viene letto due volte nel buffer della cronologia del terminale corrente;
    2. I buffer di terminali diversi non rimangono sincronizzati con il file della cronologia.
  • opzione 2:

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

    (Sì, non è necessario shopt -s histappend E sì, deve essere history -c Nel mezzo di Prompt_COMMAND) Questa versione presenta anche due importanti svantaggi:

    1. Il file della cronologia deve essere inizializzato. Deve contenere almeno una riga non vuota (può essere qualsiasi cosa).
    2. Il comando history può dare un falso output - vedi sotto.

[Modifica] "E il vincitore è ..."

  • opzione 3:

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

    Questo è quanto arriva. È l'opzione unica per far funzionare simultaneamente sia erasedups che la cronologia comune. Questa è probabilmente la soluzione finale a tutti i tuoi problemi, Aahan.


2. Perché l'opzione 2 non sembra funzionare (o: ciò che realmente non funziona come previsto)?

Come ho già detto, ognuna delle soluzioni sopra funziona in modo diverso. Ma l'interpretazione più fuorviante di come funzionano le impostazioni deriva dall'analisi dell'output del comando history. In molti casi, il comando può fornire output false. Perché? Perché viene eseguito prima la sequenza di altri comandi history contenuti nel Prompt_COMMAND! = Tuttavia, quando si utilizza la seconda o terza opzione, è possibile monitorare le modifiche dei contenuti di .bash_history (Utilizzando ad esempio watch -n1 "tail -n20 .bash_history") E vedere qual è la cronologia reale.

3. Perché l'opzione 3 è così complicata?

Tutto sta nel modo in cui erasedups funziona. Come afferma il manuale di bash, "(...) erasedups fa sì che tutte le righe precedenti corrispondenti alla riga corrente vengano rimosse dall'elenco cronologico prima che la riga venga salvata" . Quindi questo è davvero ciò che l'OP voleva (e non solo, come pensavo in precedenza, non apparire duplicati in sequenza) . Ecco perché ciascuno dei comandi history -. Deve o non può essere nel Prompt_COMMAND:

  • history -nha di essere lì prima di history -w Per leggere da .bash_history I comandi salvati da qualsiasi altro terminale,

  • history -wha di essere lì per salvare la cronologia in un file e cancellare i duplicati,

  • history -anon deve essere collocato lì invece di history -w, Perché non provoca la cancellazione di duplicati,

  • history -c È anche necessario perché impedisce di eliminare il buffer della cronologia dopo ogni comando,

  • e, infine, history -r è necessario per ripristinare il buffer della cronologia dal file, rendendo così la cronologia condivisa tra le sessioni del terminale.

126
rozcietrzewiacz

Nel tuo comando Prompt, stai usando -c interruttore. A partire dal man bash:

- c Cancella l'elenco cronologico eliminando tutte le voci

Per condividere la tua cronologia con tutti i terminali aperti, puoi utilizzare -n:

- n Leggi le righe della cronologia non già lette dal file della cronologia nell'elenco cronologico corrente. Queste sono le linee aggiunte al file della cronologia dall'inizio della sessione bash corrente.

La dimensione predefinita è anche nel manuale:

HISTSIZE Il numero di comandi da ricordare nella cronologia dei comandi (vedi STORIA di seguito). Il valore predefinito è 500.

Per salvare i comandi multilinea:

L'opzione cmdhist Shell, se abilitata, fa sì che Shell tenti di salvare ogni riga di un comando multilinea nella stessa voce della cronologia, aggiungendo punti e virgola ove necessario per preservare la correttezza sintattica. L'opzione lithist Shell fa sì che Shell salvi il comando con newline incorporate anziché punti e virgola.

Inoltre, non dovresti prefigurare i comandi HIST * con export - sono variabili solo bash non variabili ambientali: HISTCONTROL=ignoredups:erasedups è sufficiente.

8
jasonwryan

Questo è quello che mi è venuto in mente e ne sono felice finora ...

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" 

APPUNTI:

  • Sì, è complicato ... ma rimuove tutti i duplicati e conserva la cronologia all'interno di ciascun terminale!
  • Il mio HISTIGNORE ignora tutti i comandi che non hanno argomenti. Questo potrebbe non essere desiderabile da alcune persone e può essere lasciato fuori.
8
user41176

Usa questo invece:

HISTCONTROL=ignoreboth
1
verndog

Non funziona, perché ti dimentichi di:

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

Ma sembra che history -n Sia difettoso solo quando export HISTCONTROL=ignoreboth:erasedups È attivo.

Consente l'esperimento:

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

Qui attiviamo la cancellazione dei duplicati, passiamo la cronologia al file personalizzato, cancelliamo la cronologia. Dopo aver completato tutti i comandi, abbiamo un file di cronologia vuoto e un comando nella cronologia corrente.

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

Apri il secondo terminale ed esegui anche questi sei comandi. Dopo di che:

$ 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"

Ora la tua cronologia attuale ha due comandi e il file della cronologia ha:

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

Torna al primo terminale:

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

Huh ... nessuno dei comandi echo viene letto. Passare nuovamente al secondo terminale e:

$ echo "Z"
$ history -w

Ora il file della cronologia è:

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

Passa nuovamente al primo terminale:

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

Puoi vedere che il comando echo "Z" È unito a history -n.

Un altro bug è dovuto al fatto che i comandi vengono letti dalla cronologia dal numero di comando e non dal tempo di comando, credo. Mi aspetto che altri comandi echo siano apparsi nella cronologia

0
Eugen Konkov

Sono andato con una combinazione di risposte qui:

  • Voglio che la mia storia sia unita alla fine, quindi ho usato la funzione trap.
  • Voglio anche che i miei file della cronologia siano separati dagli host, quindi ho cambiato HISTFILE in modo che punti a una directory e ho nominato i file in base al nome host.
  • Ho aggiunto l'opzione ignorespace in modo da poter digitare password in chiaro e non farle visualizzare nella cronologia, ad es .: $ ./.secretfunction -user myuser -password mypassword non verrà salvato perché inizia con lo spazio.
  • Ho aggiunto history* e exit a HISTIGNORE solo per mantenere quei comandi, incluso tutto ciò che è passato come history | grep awesomecommand fuori di lì dal momento che normalmente non lo vorrei. Puoi aggiungerne altri come: logout, fg, bg, ecc.
  • Ho quindi inserito tutto nel mio file ~/.bash_aliases in modo che non sia in conflitto con gli aggiornamenti come è successo a volte.
HISTCONTROL=ignoreboth:erasedups:ignorespace
HISTIGNORE="history*:exit"
HISTFILE=~/.bash_history/.$(hostname)_history
shopt -s histappend
function historymerge {
    history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
Prompt_COMMAND="history -a; $Prompt_COMMAND"

Grep tuo ~/per Prompt_COMMAND per assicurarti di non averlo già modificato con la cronologia -a. Ho anche aggiunto il formato TIME/DATE HISTTIMEFORMAT="%x %r %Z " Mi è piaciuto, ma non ho incluso nel blocco sopra dato che è sensibile alle impostazioni locali.

0
Marlon

erasedups non taglia (come chomp in alcune lingue) gli spazi iniziali e finali. Questo è un bug Anche cancellazioni non cancella tutte le voci precedenti.

0

L'uso di una combinazione dell'opzione 3 di @ rozcietrzewiacz con una trap di uscita consentirà ai terminali di mantenere le proprie sessioni di cronologia indipendenti che convergono alla chiusura. Sembra persino funzionare bene con più sessioni su macchine diverse che condividono una home directory remota.

export HISTSIZE=5000
export HISTFILESIZE=5000
export HISTCONTROL=ignorespace:erasedups
shopt -s histappend
function historymerge {
    history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
Prompt_COMMAND="history -a; $Prompt_COMMAND"
  • La funzione historymerge carica le righe fuori sessione dal file di cronologia, le combina con la cronologia delle sessioni, scrive un nuovo file di cronologia con deduplicazione (eliminando così tutte le righe duplicate aggiunte in precedenza) e ricarica la cronologia.

  • Mantenere history -a nel Prompt minimizza il rischio di perdere la cronologia, poiché aggiorna il file della cronologia senza deduplicazione su ogni comando.

  • Infine, la trap innesca historymerge alla chiusura della sessione per un file di cronologia pulito aggiornato con i comandi della sessione chiusa più di recente gorgogliati fino alla fine del file (credo).

Con questo, ogni sessione del terminale avrà una propria storia indipendente a partire dal lancio. Trovo che sia più utile in quanto tendo ad avere diversi terminali aperti per compiti diversi (quindi voglio ripetere diversi comandi in ciascuno). È anche misericordiosamente più semplice che dare un senso a più terminali cercando costantemente di risincronizzare la loro storia ordinata in modo distribuito (anche se puoi ancora farlo deliberatamente usando la funzione historymerge con sessioni selezionate o tutti loro).

Tieni presente che i limiti delle dimensioni devono essere sufficientemente grandi da contenere la lunghezza della cronologia desiderata più il volume delle righe non deduplicate che possono essere aggiunte da tutte le sessioni attive contemporaneamente. 5000 è abbastanza per me in gran parte grazie all'ampio uso di HISTIGNORE per filtrare i comandi di basso valore di spam.

0
HonoredMule