Aggiorna la cronologia bash su altri terminali all'uscita da un terminale


15

So che questa domanda non è oscura, poiché viene posta qui continua ad aggiornare (e duplicata qui).

Quello che sto cercando di ottenere è un po 'diverso. Non mi piace l'idea che il mio prompt riscriva un file ogni volta lsche digito ( history -a; history -c; history -r).

Vorrei aggiornare il file all'uscita. È facile (in realtà, predefinito), ma è necessario aggiungere invece di riscrivere:

shopt -s histappend

Ora, quando un terminale è chiuso, vorrei rendere tutti gli altri che rimangono aperti per essere a conoscenza dell'aggiornamento.

Preferisco farlo senza controllare $PS1su ogni cosa commandche scrivo. Penso che sarebbe meglio catturare una sorta di segnale. Come lo faresti? Se non è possibile, forse un semplice cronjob?

Come possiamo risolvere questo enigma?


1
Nota che zsh lo fa immediatamente (e ha molte opzioni per mettere a punto la condivisione della cronologia).
Gilles 'SO- smetti di essere malvagio' il

Grazie @Gilles; Divertente, anni usando Linux e non ho mai provato altro bash. Forse è il momento di controllare qualcosa di nuovo, solo per divertimento.
Dr Beco,

Risposte:


15

Segnali creativi e coinvolgenti, dici? OK:

trap on_exit EXIT
trap on_usr1 USR1

on_exit() {
    history -a
    trap '' USR1
    killall -u "$USER" -USR1 bash
}

on_usr1() {
    history -n
}

Buttalo dentro .bashrce vai. Questo utilizza segnali per indicare a ogni bashprocesso di verificare la presenza di nuove voci di cronologia quando ne esce un'altra. È piuttosto orribile, ma funziona davvero.


Come funziona?

trapimposta un gestore di segnale per un segnale di sistema o per uno degli eventi interni di Bash. L' EXITevento è qualsiasi terminazione controllata della shell, mentre USR1è SIGUSR1un segnale insignificante che ci stiamo appropriando.

Ogni volta che esce la shell, noi:

  • Aggiungi esplicitamente tutta la cronologia al file.
  • Disabilita il SIGUSR1gestore e fai in modo che questa shell ignori il segnale.
  • Invia il segnale a tutti i bashprocessi in esecuzione dallo stesso utente.

Quando SIGUSR1arriva un :

  • Carica tutte le nuove voci dal file cronologico nell'elenco cronologico in memoria della shell.

A causa del modo in cui Bash maniglie segnali, non sarà effettivamente ottenere i nuovi dati storici fino a colpire Enterla prossima volta, quindi questo non fa di meglio su questo fronte che mettere history -nin PROMPT_COMMAND. Tuttavia, salva la lettura del file costantemente quando non è successo nulla e non c'è alcuna scrittura fino a quando la shell non esce.


Ci sono ancora un paio di problemi qui, tuttavia. Il primo è che la risposta predefinita a SIGUSR1è terminare la shell. Qualsiasi altro bashprocesso (ad esempio l'esecuzione di script shell) verrà interrotto. .bashrcnon viene caricato da shell non interattive. Invece, viene caricato un file chiamato daBASH_ENV : puoi impostare quella variabile nel tuo ambiente a livello globale per puntare a un file con:

trap '' USR1

in esso per ignorare il segnale in essi (che risolve il problema).

Infine, anche se questo fa quello che hai chiesto, l'ordinazione che riceverai sarà un po 'insolita. In particolare, frammenti di cronologia verranno ripetuti in diversi ordini man mano che vengono caricati e salvati separatamente. Questo è essenzialmente inerente a ciò che stai chiedendo, ma tieni presente che la cronologia delle frecce verso l'alto diventa molto meno utile a questo punto. Le sostituzioni di storia e simili saranno condivise e funzioneranno bene, comunque.


Mi chiedo se hai abilitato il timestamp all'interno del .bashrcfile e poi hai avuto qualcosa come un cronjob che si avvicina e ricorre periodicamente il file, inviando un SIGUSR1frammento secondo te, se puoi riguadagnare la cronologia cronologica della freccia in alto?
forquare,

È una soluzione accurata, ma per il fatto che altri processi terminano con USR1. Questo comportamento si verifica anche con USR2?
Dr Beco,

Aggiungerò un secondo commento, perché sono stupito. Come mai il processo associa TERM con USR1? USR1 non è qualcosa che può essere utilizzato solo dall'utente ?? È questo linux bug?? Perché altri processi stanno rilevando USR1? (So ​​che non dovrebbe essere discusso qui, ma forse lo porterò alla luce nel posto giusto)
Dr Beco,

Il comportamento predefinito di quasi tutti i segnali è di terminare; è specificato in POSIX . Non è un bug. Bash ti consentirà di specificare che il segnale verrà ignorato per tutti i suoi processi, quindi va bene per i nostri scopi.
Michael Homer,

Grazie @MichaelHomer. Questa specifica che intendevi è stata eseguita BASH_ENVcome indicato in questa risposta? O conosci un modo più standard per spegnere questo male?
Dr Beco,
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.