Aktualisieren Sie den Bash-Verlauf auf anderen Terminals, wenn Sie ein Terminal verlassen

14

Ich weiß, dass diese Frage nicht unklar ist, da sie hier weiter aktualisiert (und hier dupliziert ) wird.

Was ich versuche zu erreichen, ist ein bisschen anders. Mir gefällt die Idee nicht, dass meine Eingabeaufforderung bei jeder Eingabe eine Datei neu schreibt ls( history -a; history -c; history -r).

Ich möchte die Datei beim Beenden aktualisieren. Das ist einfach (eigentlich Standard), aber Sie müssen anhängen, anstatt neu zu schreiben:

shopt -s histappend

Wenn jetzt ein Terminal geschlossen wird, möchte ich alle anderen, die offen bleiben, auf das Update aufmerksam machen.

Ich ziehe es vor, dies zu tun, ohne $PS1bei jedem command, den ich tippe , nachzusehen. Ich denke, es wäre besser, ein Signal zu erfassen. Wie würdest du das machen? Wenn nicht möglich, vielleicht eine einfache cronjob?

Wie können wir dieses Rätsel lösen?

Dr. Beco
quelle
1
Beachten Sie, dass zsh dies sofort erledigt (und viele Optionen zur Feinabstimmung der Verlaufsfreigabe bietet).
Gilles 'SO- hör auf böse zu sein'
Danke @Gilles; Lustig, Jahre mit Linux und ich habe nie etwas anderes ausprobiert bash. Vielleicht ist es Zeit, etwas Neues zu prüfen, nur zum Spaß.
Dr. Beco

Antworten:

14

Kreative und involvierende Signale, sagst du? IN ORDNUNG:

trap on_exit EXIT
trap on_usr1 USR1

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

on_usr1() {
    history -n
}

Chuck das rein .bashrcund los. Hierbei werden Signale verwendet, um jedem bashProzess mitzuteilen, dass beim Beenden eines anderen Prozesses nach neuen Verlaufseinträgen gesucht werden soll. Das ist ziemlich schrecklich, aber es funktioniert wirklich.


Wie funktioniert es?

trapLegt einen Signal-Handler für ein Systemsignal oder eines der internen Ereignisse von Bash fest. Das EXITEreignis ist eine kontrollierte Beendigung der Shell, während USR1es SIGUSR1sich um ein bedeutungsloses Signal handelt, das wir uns zu Eigen machen.

Wann immer die Shell beendet wird, werden wir:

  • Hängen Sie den gesamten Verlauf explizit an die Datei an.
  • Deaktivieren Sie den SIGUSR1Handler und lassen Sie diese Shell das Signal ignorieren .
  • Senden Sie das Signal an alle laufenden bashProzesse desselben Benutzers.

Wenn ein SIGUSR1kommt, wir:

  • Laden Sie alle neuen Einträge aus der Verlaufsdatei in die speicherinterne Verlaufsliste der Shell.

Aufgrund der Art und Weise Bash Griff Signale, werden Sie nicht tatsächlich die neuen History - Daten, bis Sie schlagen Enterdas nächste Mal, so dass dies nicht besser an dieser Front macht als Putting history -nin PROMPT_COMMAND. Es spart jedoch, die Datei ständig zu lesen, wenn nichts passiert ist, und es wird überhaupt nicht geschrieben, bis die Shell beendet wird.


Hier gibt es jedoch noch einige Probleme. Die erste ist, dass die Standardantwort auf SIGUSR1das Beenden der Shell ist. Alle anderen bashProzesse (z. B. das Ausführen von Shell-Skripten) werden abgebrochen. .bashrcwird nicht von nicht interaktiven Shells geladen. Stattdessen wird eine Datei mit dem Namen BASH_ENVgeladen : Sie können diese Variable in Ihrer Umgebung global so einstellen, dass sie auf eine Datei zeigt mit:

trap '' USR1

darin das Signal in ihnen zu ignorieren (was das Problem löst).

Obwohl dies genau das tut, wonach Sie gefragt haben, wird die Reihenfolge, die Sie erhalten, etwas ungewöhnlich sein. Insbesondere werden Teile der Historie in unterschiedlicher Reihenfolge wiederholt, wenn sie separat geladen und gespeichert werden. Dies ist im Wesentlichen das, wonach Sie fragen. Beachten Sie jedoch, dass die Aufwärtspfeil-Historie an dieser Stelle weitaus weniger nützlich ist. Geschichtsersetzungen und dergleichen werden jedoch geteilt und funktionieren gut.

Michael Homer
quelle
Ich frage mich, ob Sie die Zeitstempelung in der .bashrcDatei aktiviert haben und dann in regelmäßigen Abständen so etwas wie einen Cronjob durchgeführt und die Datei neu sortiert haben und ein Snippet nach Ihren Wünschen gesendet haben SIGUSR1, um festzustellen, ob Sie die chronologische Aufwärtspfeil-Historie wiederherstellen konnten.
Forquare
Es ist eine ordentliche Lösung, aber für die Tatsache, dass andere Prozesse auf USR1 enden. Tritt dieses Verhalten auch bei USR2 auf?
Dr. Beco
Ich werde einen zweiten Kommentar hinzufügen, weil ich erstaunt bin. Wie kommt es, dass der Prozess TERM mit USR1 verknüpft? Ist USR1 nicht nur für den Benutzer bestimmt? Ist das etwas linux bug?? Warum fangen andere Prozesse USR1? (Ich weiß, es ist nicht dazu gedacht, hier besprochen zu werden, aber vielleicht werde ich dies an der richtigen Stelle ans Licht bringen)
Dr. Beco
Das Standardverhalten fast aller Signale ist das Beenden. es ist in POSIX angegeben . Es ist kein Fehler. Mit Bash können Sie festlegen, dass das Signal bei allen Prozessen ignoriert wird. Für unsere Zwecke ist das also in Ordnung.
Michael Homer
Danke @MichaelHomer. Ist diese Spezifikation, die Sie gemeint haben, BASH_ENVwie in dieser Antwort angegeben? Oder kennen Sie eine Standardmethode, um dieses Böse auszuschalten?
Dr. Beco