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


85

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 al .bashrcfile 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 singolo comando (disattivato per impostazione predefinita)
  • qual è la dimensione della cronologia predefinita e la dimensione del file della cronologia?

urto! chiunque? Niente funziona. Questo potrebbe essere un problema con Fedora 15 (con Gnome 3 e in esecuzione su una macchina virtuale host Windows)?
its_me

Per favore non "sbattere" i post qui. Se non ricevono risposta, è necessario chiedere in modo più chiaro, includere i bit giusti di indizi di contesto o qualcosa del genere. Se hai bisogno di attenzione sui tuoi post, puoi emettere taglie che aiutano più persone a prestare loro più attenzione.
Caleb,

1
Sei sicuro di usare anche bash? ( echo $SHELL). Le impostazioni funzionano se le esegui manualmente dalla shell aperta? Ovviamente, poiché funzionano per così tanti altri, le impostazioni sono giuste, le stai solo implementando in modo sbagliato. E nessun Fedora15 / Gnome3 / essendo una macchina virtuale ha poco a che fare con l'effettiva funzione di bash.
Caleb,

@Caleb, prima mi dispiace per aver sbattuto la posta. Inoltre, ho fatto del mio meglio per essere molto chiaro. No, non li ho emessi nella shell. Li ho appena copiati e incollati nel .bashrcfile. È sbagliato? Puoi aggiungere una "risposta" a questo post con gli attuali comandi della shell? (per favore,
abbi pazienza

1
Tutto ciò che scrivi negli script o .bashrcSONO veri e propri comandi di shell. Gli script sono solo una serie di comandi shell. Anche la modifica che hai apportato di recente rimuovendo il exportbit è stata una cattiva idea, che dovrebbe essere mantenuta.
Caleb,

Risposte:


120

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 fare in modo che la cronologia venga "trasferita" su un altro terminale (aggiornato), è necessario premere Enteril terminale, dove desidera recuperare la cronologia.

  • 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 di cronologia viene letto due volte nel buffer di 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 histappende sì, deve essere history -c nel mezzo di PROMPT_COMMAND) Questa versione ha 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 historycomando 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' unica opzione per far erasedupsfunzionare simultaneamente sia la storia comune. Questa è probabilmente la soluzione finale a tutti i tuoi problemi, Aahan.


2. Perché l' opzione 2 non sembra funzionare (o: cosa non funziona davvero 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 historycomando . In molti casi, il comando può dare un output falso . Perché? Perché viene eseguito prima della sequenza di altri historycomandi contenuta nel PROMPT_COMMAND! Tuttavia, quando si utilizza la seconda o la terza opzione, è possibile monitorare le modifiche dei .bash_historycontenuti (usando watch -n1 "tail -n20 .bash_history"ad esempio) e vedere qual è la storia reale.

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

Tutto sta nel modo in cui erasedupsfunziona. Come afferma il manuale di bash, "(...) erasedupsfa 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 avere duplicati che compaiono in sequenza ) . Ecco perché ognuno dei history -.comandi deve o non può essere nel PROMPT_COMMAND:

  • history -n deve essere lì prima history -wdi leggere dai .bash_historycomandi salvati da qualsiasi altro terminale,

  • history -w deve essere lì per salvare la cronologia su file e cancellare i duplicati,

  • history -a non deve essere posizionato lì invece di history -w, perché non provoca la cancellazione di duplicati,

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

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


2
+1 per "Ma l'interpretazione più fuorviante di come funzionano le impostazioni deriva dall'analisi dell'output del comando history." Penso che questo sia il nocciolo della questione del PO. Deduzione eccellente.
Jasonwryan,

2
Finalmente ho visto il tuo punto. Con "duplicati" intendevi qualcos'altro oltre a me stesso. Mi sono concentrato solo sulle sequenze dello stesso comando . Aggiornato la mia risposta - vedi "opzione 3". Inoltre, nel tuo caso, per testare come funziona la cronologia, dovresti effettivamente utilizzare watch "tail -n 20 .bash_history"invece di tail -f .bash_history.
rozcietrzewiacz,

2
L'opzione 3 ha appena cancellato tutte le mie 100.000 righe di storia :( (bash 3.2.25 (1)-release)
Felipe Alvarez,

2
history -cè necessario anche perché impedisce il cestino del buffer della cronologia dopo ogni comando Perché si verifica questo cestino?
Piotr Dobrogost,

2
La soluzione 3 in realtà non funziona. È estremamente difettoso e dipende dall'ordine in cui gli utenti colpiscono entrano in diversi terminali. Spesso si tradurranno in comandi persi, specialmente quando si passa da un terminale all'altro. Fonte: provalo.
6

8

Nel comando rapido, si utilizza l' -copzione. Da 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 shell cmdhist , se abilitata, fa tentare alla shell 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 shell lithist fa sì che la 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.


Quindi, questo export PROMPT_COMMAND="history -a; history -n; history -r; $PROMPT_COMMAND"è corretto? Inoltre, sai come posso fare in modo che il file della cronologia memorizzi i comandi multilinea come un singolo comando (che è disattivato per impostazione predefinita) ??
its_me

1
Sì. Secondo la pagina man sopra citata, shopt -s cmdhistsalverà più righe.
Jasonwryan,

ok, ci ho provato tutti. Sembra che HISTCONTROL=ignoredups:erasedupsnon funzioni. Ho anche provato ad avere solo questo nel .bashrcfile (tra le funzioni personalizzate). Qualche idea di cosa potrebbe esserci di sbagliato? Sto usando Fedora 15 su una macchina virtuale - - Host di Windows 7.
its_me

Assicurarsi che non vi sia nulla negli altri file di avvio, come /etc/bashrc, .bash_profileecc. , Che lo sovrascrive.
Jasonwryan,

Non vedo problemi con il .bash_profilefile. Per quanto riguarda il contenuto in /etc/bashrcHo messo qui, per favore dai un'occhiata - pastebin.com/Uae6sE6s
its_me

8

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!
  • My HISTIGNOREignora tutti i comandi che non hanno argomenti. Questo potrebbe non essere desiderabile da alcune persone e può essere lasciato fuori.


0

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 -nsia solo buggy quando export HISTCONTROL=ignoreboth:erasedupsè in vigore.

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

Eh ... nessuno dei echocomandi 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 echo "Z"comando è unito a history -n.

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


0

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

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.