Historique Bash: les paramètres «ignoredups» et «erasedups» sont en conflit avec l'historique commun des sessions.


85

Tout d'abord, il ne s'agit pas d'un duplicata d'aucun thread existant sur SE. J'ai lu ces deux discussions ( 1ère , 2ème ) sur une meilleure histoire de Bash, mais aucune des réponses ne fonctionne - - je suis sur Fedora 15 d'ailleurs.

J'ai ajouté ce qui suit au .bashrcfichier dans le répertoire utilisateur (/ home / aahan /), et cela ne fonctionne pas. Quelqu'un a un indice?

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

Ok c'est ce que je veux avec l'historique bash (priorité):

  • ne stocke pas les doublons, efface les existants
  • partager immédiatement l'historique avec tous les terminaux ouverts
  • toujours ajouter l'histoire, pas l'écraser
  • stocke les commandes multi-lignes en une seule commande (désactivée par défaut)
  • Quelle est la taille de l'historique et la taille du fichier d'historique par défaut?

bosse! n'importe qui? Rien ne fonctionne. Cela pourrait-il être un problème avec Fedora 15 (avec Gnome 3 et s’exécutant sur une machine virtuelle hôte Windows)?
its_me

S'il vous plaît, ne "bosse" pas de messages ici. Si on ne leur répond pas, vous devez demander plus clairement, inclure les bons indices de contexte, ou quelque chose du genre. Si vous avez besoin d'attention sur vos messages, vous pouvez émettre des primes qui permettent d'attirer davantage d'attention.
Caleb

1
Êtes-vous sûr que vous utilisez même bash? ( echo $SHELL) Les paramètres fonctionnent-ils si vous les exécutez manuellement à partir de votre shell ouvert? Évidemment, comme ils fonctionnent pour tant d’autres, les réglages sont corrects, vous ne les implémentez pas. Et aucune Fedora15 / Gnome3 / être une machine virtuelle n’a que peu à voir avec la fonction réelle de bash.
Caleb

@Caleb, d'abord désolé de cogner le poste. De plus, j'ai fait de mon mieux pour être très clair. Non, je ne les ai pas publiés dans la coquille. Je viens de les copier-coller dans un .bashrcfichier. Est-ce faux? Pouvez-vous ajouter une "réponse" à ce message avec les commandes du shell? (s'il vous plaît supporter avec ma noob-ity.)
its_me

1
Tout ce que vous écrivez dans des scripts ou dans .bashrcdes commandes shell ARE. Les scripts ne sont que des séries de commandes shell. De plus, le montage que vous avez récemment fait en supprimant le exportbit était une mauvaise idée, qui devrait être conservée.
Caleb

Réponses:


120

C’est un comportement vraiment intéressant et j’avoue que j’ai largement sous-estimé la question au début. Mais d'abord les faits:

1. Qu'est-ce qui fonctionne

La fonctionnalité peut être obtenue de plusieurs manières, bien que chacune fonctionne un peu différemment. Notez que, dans chaque cas, pour que l'historique soit "transféré" vers un autre terminal (mis à jour), il faut appuyer Enterdans le terminal sur lequel il souhaite récupérer l'historique.

  • Option 1:

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

    Cela a deux inconvénients:

    1. Lors de la connexion (ouverture d’un terminal), la dernière commande du fichier d’historique est lue deux fois dans le tampon d’historique du terminal actuel;
    2. Les mémoires tampons des différents terminaux ne restent pas synchronisées avec le fichier d’historique.
  • Option 2:

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

    (Oui, pas besoin shopt -s histappendet oui, il doit être history -c au milieu de PROMPT_COMMAND) Cette version présente également deux inconvénients importants:

    1. Le fichier d'historique doit être initialisé. Il doit contenir au moins une ligne non vide (peut être n'importe quoi).
    2. La historycommande peut donner un faux résultat - voir ci-dessous.

[Edit] "Et le gagnant est ..."

  • option 3:

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

    Ceci est aussi loin que possible. C’est la seule option possible pour que les deux erasedupset l’histoire commune fonctionnent simultanément. C'est probablement la solution finale à tous vos problèmes, Aahan.


2. Pourquoi l' option 2 ne semble pas fonctionner (ou: qu'est - ce qui ne fonctionne pas comme prévu)?

Comme je l'ai mentionné, chacune des solutions ci-dessus fonctionne différemment. Mais l'interprétation la plus trompeuse du fonctionnement des paramètres provient de l'analyse du résultat de la historycommande . Dans de nombreux cas, la commande peut donner une sortie erronée . Pourquoi? Parce qu'il est exécuté avant la séquence des autres historycommandes contenues dans le PROMPT_COMMANDfichier! Cependant, lorsque vous utilisez la deuxième ou la troisième option, vous pouvez surveiller les modifications de .bash_historycontenu (en utilisant watch -n1 "tail -n20 .bash_history"par exemple) et voir quel est l'historique réel.

3. Pourquoi l' option 3 est-elle si compliquée?

Tout se trouve dans la façon dont erasedupsfonctionne. Comme l'indique le manuel bash, "(...) erasedupssupprime toutes les lignes précédentes correspondant à la ligne actuelle de la liste de l'historique avant que cette ligne ne soit enregistrée" . Donc, c’est vraiment ce que le PO souhaitait (et pas simplement, comme je le pensais précédemment, ne pas avoir de doublons apparaissant dans l’ordre ) . Voici pourquoi chacune des history -.commandes doit ou ne peut pas être dans le PROMPT_COMMAND:

  • history -n doit être là avant history -wde lire .bash_historyles commandes sauvegardées de n’importe quel autre terminal,

  • history -w doit être présent pour sauvegarder l’historique dans le fichier et effacer les doublons,

  • history -a ne doit pas être placé là au lieu de history -w, car cela ne déclenche pas l’effacement des doublons,

  • history -cest également nécessaire car il évite de détruire le tampon d’historique après chaque commande,

  • et enfin, history -rest nécessaire pour restaurer le tampon d’historique à partir d’un fichier, rendant ainsi l’historique partagé entre les sessions de terminal.


2
+1 pour "Mais l'interprétation la plus trompeuse du fonctionnement des paramètres provient de l'analyse du résultat de la commande d'historique." Je pense que c'est le cœur du problème du PO. Excellente déduction.
jasonwryan

2
J'ai enfin compris votre argument. Par «doublons», vous vouliez dire autre chose que moi. Je me suis concentré uniquement sur les séquences de la même commande . Mise à jour de ma réponse - voir "option 3". En outre, dans votre cas, pour tester le fonctionnement de l’historique, vous devez utiliser à la watch "tail -n 20 .bash_history"place du tail -f .bash_history.
rozcietrzewiacz

2
Option 3 vient d'effacer toutes mes 100 000 lignes d'histoire :( (version 3.2.25 (1) - release)
Felipe Alvarez le

2
history -cest également nécessaire car il empêche la suppression du tampon de l'historique après chaque commande. Pourquoi cette suppression se produit-elle?
Piotr Dobrogost

2
Votre solution 3 ne fonctionne pas réellement. C'est extrêmement bogué et dépend de l'ordre dans lequel les utilisateurs tapent dans différents terminaux. Il en résultera souvent des commandes perdues, en particulier lors de la commutation entre les terminaux. Source: essayé.
6cef

8

Dans votre commande d'invite, vous utilisez le -ccommutateur. De man bash:

-c   Effacer l'historique en supprimant toutes les entrées

Pour partager votre historique avec tous les terminaux ouverts, vous pouvez utiliser -n:

-n   Lit les lignes d’historique non lues du fichier d’historique dans la liste d’historique actuelle. Ce sont des lignes ajoutées au fichier d’historique depuis le début de la session bash en cours.

La taille par défaut est également dans le manuel:

HISTSIZE Nombre de commandes à mémoriser dans l'historique des commandes (voir HISTORIQUE ci-dessous). La valeur par défaut est 500.

Pour enregistrer des commandes multilignes:

La cmdhist option shell, si elle est activée, provoque la coquille pour tenter de sauver chaque ligne d'une commande sur plusieurs lignes dans la même entrée de l' histoire, en ajoutant des points - virgules si nécessaire pour préserver l' exactitude de syntaxique. L' option shell lithist amène le shell à enregistrer la commande avec des nouvelles lignes incorporées au lieu de points-virgules.

En outre, vous ne devriez pas préfacer les commandes HIST * avec export- ce sont des variables uniquement bash et non des variables environnementales: HISTCONTROL=ignoredups:erasedupsest suffisant.


Donc export PROMPT_COMMAND="history -a; history -n; history -r; $PROMPT_COMMAND"c'est correct? En outre, savez-vous comment je peux créer des commandes multilignes en tant que commande unique (qui est désactivée par défaut)?
its_me

1
Oui. Selon la page de manuel citée ci-dessus, vous shopt -s cmdhistéconomiserez plusieurs lignes.
jasonwryan

d'accord, j'ai tout essayé. On dirait que ça HISTCONTROL=ignoredups:erasedupsne marche pas. J'ai aussi essayé d'avoir cela dans le .bashrcfichier (parmi les fonctions personnalisées). Une idée de ce qui pourrait être faux? J'utilise Fedora 15 sur une machine virtuelle - - Hôte Windows 7.
its_me

Assurez-vous qu'il n'y a rien dans les autres fichiers de démarrage, tels que /etc/bashrc, .bash_profileetc., qui le remplace.
jasonwryan

Je ne vois pas de problèmes avec le .bash_profilefichier. En ce qui concerne le contenu, /etc/bashrcje le mets ici, jetez un coup d’œil - pastebin.com/Uae6sE6s
its_me

8

C’est ce que j’ai trouvé et j'en suis heureux jusqu’à présent…

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" 

REMARQUES:

  • Oui, c'est compliqué ... mais, il supprime tous les doublons tout en préservant la chronologie au sein de chaque terminal!
  • Mon HISTIGNOREignore toutes les commandes sans arguments. Cela peut ne pas être souhaitable pour certaines personnes et peut être laissé de côté.


0

Cela ne fonctionne pas, car vous oubliez:

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

Mais il semble que ce history -nsoit simplement un buggy quand il export HISTCONTROL=ignoreboth:erasedupsest en vigueur.

Permet d'expérimenter:

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

Ici, nous activons l’effacement des doublons, commutons l’historique en fichier personnalisé, effaceons l’historique. Une fois toutes les commandes terminées, nous avons un fichier d’historique vide et une commande dans l’historique actuel.

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

Ouvrez le deuxième terminal et exécutez ces six commandes aussi. Après ça:

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

Maintenant, votre historique actuel a deux commandes et le fichier d’historique a:

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

Retour au premier terminal:

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

Euh ... aucune des echocommandes n'est lue. Passez à nouveau au deuxième terminal et:

$ echo "Z"
$ history -w

Maintenant le fichier historique est:

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

Revenez au premier terminal:

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

Vous pouvez voir que cette echo "Z"commande est fusionnée history -n.

Un autre bogue est dû au fait que les commandes sont lues dans l'historique par numéro de commande et non par heure de commande, je pense. J'espère que d'autres echocommandes sont apparues dans l'historique


0

effacé ne supprime pas (comme chomp dans certaines langues) les espaces de début et de fin. C'est un bug. De même, effacé ne supprime pas toutes les entrées précédentes.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.