Mettre à jour l'historique de bash sur d'autres terminaux lors de la fermeture d'un terminal

15

Je sais que cette question n'est pas obscure, car elle est posée ici, continuez à mettre à jour (et dupliquez ici).

Ce que j'essaie de réaliser est un peu différent. Je n'aime pas l'idée de ma réécriture rapide d'un fichier chaque fois que lsje tape ( history -a; history -c; history -r).

Je voudrais mettre à jour le fichier à la sortie. C'est facile (en fait, par défaut), mais vous devez ajouter au lieu de réécrire:

shopt -s histappend

Maintenant, lorsqu'un terminal est fermé, je voudrais que tous les autres qui restent ouverts soient informés de la mise à jour.

Je préfère le faire sans vérifier via $PS1tous ceux commandque je tape. Je pense qu'il serait préférable de capturer une sorte de signal. Comment feriez-vous cela? Si ce n'est pas possible, peut-être un simple cronjob?

Comment pouvons-nous résoudre ce casse-tête?

Dr Beco
la source
1
Notez que zsh le fait hors de la boîte (et dispose de nombreuses options pour affiner le partage de l'historique).
Gilles 'SO- arrête d'être méchant'
Merci @Gilles; Drôle, des années d'utilisation de Linux et je n'ai jamais rien essayé d'autre bash. Peut-être qu'il est temps de vérifier quelque chose de nouveau, juste pour le plaisir.
Dr Beco

Réponses:

15

Des signaux créatifs et impliquant, dites-vous? D'ACCORD:

trap on_exit EXIT
trap on_usr1 USR1

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

on_usr1() {
    history -n
}

Jetez cela .bashrcet partez. Cela utilise des signaux pour indiquer à chaque bashprocessus de vérifier les nouvelles entrées d'historique quand un autre se ferme. C'est assez horrible, mais ça marche vraiment.


Comment ça marche?

trapdéfinit un gestionnaire de signaux pour un signal système ou l'un des événements internes de Bash. L' EXITévénement est une terminaison contrôlée du shell, alors qu'il USR1s'agit d' SIGUSR1un signal insignifiant que nous nous approprions.

Chaque fois que le shell sort, nous:

  • Ajoutez explicitement tout l'historique au fichier.
  • Désactivez le SIGUSR1gestionnaire et faites en sorte que ce shell ignore le signal.
  • Envoyez le signal à tous les bashprocessus en cours d'exécution du même utilisateur.

Quand un SIGUSR1arrive, nous:

  • Chargez toutes les nouvelles entrées du fichier d'historique dans la liste d'historique en mémoire du shell.

En raison de la façon dont les signaux poignées Bash, vous ne serez pas en réalité les nouvelles données d'histoire jusqu'à ce que vous frappez Enterla prochaine fois, si cela ne fait pas mieux sur ce plan que la mise history -nen PROMPT_COMMAND. Il enregistre la lecture du fichier en permanence quand rien ne s'est passé, cependant, et il n'y a aucune écriture du tout jusqu'à ce que le shell se termine.


Il reste cependant quelques problèmes ici. La première est que la réponse par défaut à SIGUSR1est de terminer le shell. Tous les autres bashprocessus (exécutant des scripts shell, par exemple) seront tués. .bashrcn'est pas chargé par des shells non interactifs. Au lieu de cela, un fichier nommé par BASH_ENVest chargé : vous pouvez définir cette variable dans votre environnement globalement pour pointer vers un fichier avec:

trap '' USR1

en elle pour ignorer le signal en eux (ce qui résout le problème).

Enfin, bien que cela fasse ce que vous avez demandé, la commande que vous recevrez sera un peu inhabituelle. En particulier, des morceaux d'historique seront répétés dans différents ordres au fur et à mesure qu'ils sont chargés et enregistrés séparément. C'est essentiellement inhérent à ce que vous demandez, mais sachez que l'historique des flèches vers le haut devient beaucoup moins utile à ce stade. Les substitutions d'histoire et autres seront partagées et fonctionneront bien, cependant.

Michael Homer
la source
Je me demande si vous avez activé l'horodatage dans le .bashrcfichier, puis que quelque chose comme un cronjob est venu et a utilisé le fichier périodiquement, en envoyant un SIGUSR1extrait selon vous, si vous pouviez retrouver l'historique chronologique de la flèche vers le haut?
forquare
C'est une solution intéressante, mais pour le fait, d'autres processus se terminent sur USR1. Ce problème se produit-il également avec USR2?
Dr Beco
J'ajouterai un deuxième commentaire, car je suis étonné. Comment se fait-il que le processus associe TERM à USR1? N'est-ce pas USR1 quelque chose à utiliser uniquement par l'utilisateur ?? Est-ce un peu linux bug?? Pourquoi d'autres processus attrapent USR1? (Je sais que ce n'est pas censé être discuté ici, mais je vais peut-être mettre cela en lumière au bon endroit)
Dr Beco
Le comportement par défaut de presque tous les signaux est de se terminer; il est spécifié dans POSIX . Ce n'est pas un bug. Bash vous permettra de spécifier que le signal sera ignoré pour tous ses processus, donc c'est très bien pour nous.
Michael Homer
Merci @MichaelHomer. Est-ce que cette spécification que vous vouliez dire est faite BASH_ENVcomme indiqué dans cette réponse? Ou connaissez-vous un moyen plus standard d'éteindre ce mal?
Dr Beco