J'ai toujours plus d'un terminal ouvert. De deux à dix, faisant divers morceaux et bobs. Supposons maintenant que je redémarre et ouvre un autre ensemble de terminaux. Certains se souviennent de certaines choses, certains oublient.
Je veux une histoire qui:
ls
dans un, je passe à un autre terminal déjà en cours d'exécution, puis je presse, ls
apparaît)Est-ce que je peux faire pour que bash fonctionne plus comme ça?
Ajoutez ce qui suit à ~/.bashrc
# Avoid duplicates
HISTCONTROL=ignoredups:erasedups
# When the Shell exits, append to the history file instead of overwriting it
shopt -s histappend
# After each command, append to the history file and reread it
Prompt_COMMAND="${Prompt_COMMAND:+$Prompt_COMMAND$'\n'}history -a; history -c; history -r"
Donc, c'est tout mon histoire .bashrc
chose:
export HISTCONTROL=ignoredups:erasedups # no duplicate entries
export HISTSIZE=100000 # big big history
export HISTFILESIZE=100000 # big big history
shopt -s histappend # append to history, don't overwrite it
# Save and reload the history after each command finishes
export Prompt_COMMAND="history -a; history -c; history -r; $Prompt_COMMAND"
Testé avec bash 3.2.17 sur Mac OS X 10.5, bash 4.1.7 sur 10.6.
Voici ma tentative de partage d'historique de session Bash. Cela permettra le partage de l'historique entre les sessions bash de manière à ce que le compteur d'historique ne soit pas mélangé et l'expansion de l'historique comme !number
Fonctionnera (avec certaines contraintes).
Utilisation de Bash version 4.1.5 sous Ubuntu 10.04 LTS (Lucid Lynx).
HISTSIZE=9000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups
_bash_history_sync() {
builtin history -a #1
HISTFILESIZE=$HISTSIZE #2
builtin history -c #3
builtin history -r #4
}
history() { #5
_bash_history_sync
builtin history "$@"
}
Prompt_COMMAND=_bash_history_sync
Ajoutez la ligne qui vient d'être entrée au $HISTFILE
(La valeur par défaut est .bash_history
). Cela fera augmenter $HISTFILE
D'une ligne.
Si vous définissez la variable spéciale $HISTFILESIZE
Sur une valeur, Bash tronquera $HISTFILE
Pour ne pas dépasser $HISTFILESIZE
En supprimant les entrées les plus anciennes.
Effacez l'historique de la session en cours. Cela réduira le compteur d'historique du montant de $HISTSIZE
.
Lisez le contenu de $HISTFILE
Et insérez-le dans l'historique de la session en cours d'exécution. cela augmentera le compteur d'historique du nombre de lignes dans $HISTFILE
. Notez que le nombre de lignes de $HISTFILE
N'est pas nécessairement $HISTFILESIZE
.
La fonction history()
remplace l'historique intégré pour s'assurer que l'historique est synchronisé avant son affichage. Ceci est nécessaire pour l'expansion de l'historique en nombre (plus d'informations à ce sujet plus tard).
L'étape 1 garantit que la commande de la session en cours d'exécution est écrite dans le fichier d'historique global.
L'étape 4 garantit que les commandes des autres sessions sont lues dans l'historique de session en cours.
Étant donné que l'étape 4 augmentera le compteur d'historique, nous devons réduire le compteur d'une manière ou d'une autre. Cela se fait à l'étape 3.
À l'étape 3, le compteur d'historique est réduit de $HISTSIZE
. À l'étape 4, le compteur d'historique est augmenté du nombre de lignes dans $HISTFILE
. À l'étape 2, nous nous assurons que le nombre de lignes de $HISTFILE
Est exactement $HISTSIZE
(Cela signifie que $HISTFILESIZE
Doit être le même que $HISTSIZE
).
Lorsque vous utilisez l'extension d'historique par numéro, vous devez toujours rechercher le nombre immédiatement avant de l'utiliser. Cela signifie qu'aucun affichage d'invite bash entre la recherche du numéro et son utilisation. Cela signifie généralement pas d'entrée et pas de ctrl + c.
Généralement, une fois que vous avez plus d'une session Bash, il n'y a aucune garantie que l'expansion d'un historique en nombre conserve sa valeur entre deux affichages d'invite Bash. Parce que lorsque Prompt_COMMAND
Est exécuté, l'historique de toutes les autres sessions Bash est intégré à l'historique de la session en cours. Si une autre session bash a une nouvelle commande, les numéros d'historique de la session en cours seront différents.
Je trouve cette contrainte raisonnable. De toute façon, je dois chercher le numéro à chaque fois parce que je ne me souviens pas de chiffres historiques arbitraires.
Habituellement, j'utilise l'extension historique par numéro comme ceci
$ history | grep something #note number
$ !number
Je recommande d'utiliser les options Bash suivantes.
## reedit a history substitution line if it failed
shopt -s histreedit
## edit a recalled history line before executing
shopt -s histverify
L'exécution de la commande d'historique dirigée vers n'importe quoi entraînera cette commande à être répertoriée deux fois dans l'historique. Par exemple:
$ history | head
$ history | tail
$ history | grep foo
$ history | true
$ history | false
Tous seront répertoriés deux fois dans l'historique. Je ne sais pas pourquoi.
Modifiez la fonction _bash_history_sync()
pour qu'elle ne s'exécute pas à chaque fois. Par exemple, il ne doit pas s'exécuter après un CTRL+C
Sur l'invite. J'utilise souvent CTRL+C
Pour supprimer une longue ligne de commande lorsque je décide que je ne veux pas exécuter cette ligne. Parfois, je dois utiliser CTRL+C
Pour arrêter un script d'achèvement Bash.
Les commandes de la session en cours doivent toujours être les plus récentes de l'historique de la session en cours. Cela aura également pour effet secondaire qu'un numéro d'historique donné conserve sa valeur pour les entrées d'historique de cette session.
Je ne connais aucun moyen d'utiliser bash
. Mais c'est l'une des fonctionnalités les plus populaires de zsh
.
Personnellement, je préfère zsh
plutôt que bash
donc je recommande de l'essayer.
Voici la partie de mon .zshrc
qui traite de l'histoire:
SAVEHIST=10000 # Number of entries
HISTSIZE=10000
HISTFILE=~/.zsh/history # File
setopt APPEND_HISTORY # Don't erase history
setopt EXTENDED_HISTORY # Add additional data to history like timestamp
setopt INC_APPEND_HISTORY # Add immediately
setopt HIST_FIND_NO_DUPS # Don't show duplicates in search
setopt HIST_IGNORE_SPACE # Don't preserve spaces. You may want to turn it off
setopt NO_HIST_BEEP # Don't beep
setopt SHARE_HISTORY # Share history between session/terminals
Pour ce faire, vous devrez ajouter deux lignes à votre ~/.bashrc
:
shopt -s histappend
Prompt_COMMAND="history -a;history -c;history -r;$Prompt_COMMAND"
De man bash
:
Si l'option shell histappend est activée (voir la description de shopt sous Shell BUILTIN COMMANDS ci-dessous), les lignes sont ajoutées au fichier d'historique, sinon le fichier d'historique est écrasé.
Vous pouvez modifier votre invite BASH pour exécuter "history -a" et "history -r" que Muerr a suggéré:
savePS1=$PS1
(au cas où vous gâcher quelque chose, ce qui est presque garanti)
PS1=$savePS1`history -a;history -r`
(notez qu'il s'agit de back-ticks; ils exécuteront history -a et history -r à chaque invite. Puisqu'ils ne produisent aucun texte, votre invite sera inchangée.
Une fois que vous avez configuré votre variable PS1 comme vous le souhaitez, définissez-la de manière permanente dans votre fichier ~/.bashrc.
Si vous souhaitez revenir à votre invite d'origine pendant le test, procédez comme suit:
PS1=$savePS1
J'ai fait des tests de base à ce sujet pour m'assurer que cela fonctionne, mais je ne peux pas parler des effets secondaires de l'exécution de history -a;history -r
à chaque invite.
Si vous avez besoin d'une solution de synchronisation d'historique bash ou zsh qui résout également le problème ci-dessous, consultez-la sur http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-Shell.html
Le problème est le suivant: j'ai deux fenêtres Shell A et B. Dans la fenêtre Shell A, j'exécute sleep 9999
, et (sans attendre la fin du sommeil) dans la fenêtre Shell B, je veux pouvoir voir sleep 9999
dans l'histoire de bash.
La raison pour laquelle la plupart des autres solutions ne résoudront pas ce problème est qu'elles écrivent leurs modifications d'historique dans le fichier d'historique à l'aide de Prompt_COMMAND
ou PS1
, qui s'exécutent tous deux trop tard, uniquement après le sleep 9999
la commande est terminée.
Bon, donc finalement cela m'a ennuyé de trouver une solution décente:
# Write history after each command
_bash_history_append() {
builtin history -a
}
Prompt_COMMAND="_bash_history_append; $Prompt_COMMAND"
Ce que cela fait est une sorte de fusion de ce qui a été dit dans ce fil, sauf que je ne comprends pas pourquoi rechargez-vous l'historique global après chaque commande. Je me soucie très rarement de ce qui se passe dans les autres terminaux, mais je lance toujours une série de commandes, disons dans un terminal:
make
ls -lh target/*.foo
scp target/artifact.foo vm:~/
(Exemple simplifié)
Et dans un autre:
pv ~/test.data | nc vm:5000 >> output
less output
mv output output.backup1
Pas question que je veuille que la commande soit partagée
Vous pouvez utiliser history -a
pour ajouter l'historique de la session en cours au fichier historique, puis utilisez history -r
sur les autres terminaux pour lire le fichier historique.
Voici une alternative que j'utilise. C'est lourd mais cela résout le problème mentionné par @axel_c où parfois vous souhaiterez peut-être avoir une instance d'historique distincte dans chaque terminal (une pour make, une pour la surveillance, une pour vim, etc.).
Je garde un fichier historique annexé distinct que je mets constamment à jour. J'ai le mappage suivant sur un raccourci clavier:
history | grep -v history >> ~/master_history.txt
Cela ajoute tout l'historique du terminal actuel à un fichier appelé master_history.txt dans votre répertoire personnel.
J'ai également un raccourci clavier distinct pour rechercher dans le fichier historique principal:
cat /home/toby/master_history.txt | grep -i
J'utilise le chat | grep car il laisse le curseur à la fin pour entrer dans mon expression régulière. Une façon moins laide de le faire serait d'ajouter quelques scripts à votre chemin pour accomplir ces tâches, mais les raccourcis fonctionnent à mes fins. Je vais également périodiquement extraire l'historique des autres hôtes sur lesquels j'ai travaillé et l'ajouter à mon fichier master_history.txt.
Il est toujours agréable de pouvoir rechercher rapidement et trouver cette regex délicate que vous avez utilisée ou cette étrange doublure Perl que vous avez inventée il y a 7 mois.
Je peux offrir un correctif pour ce dernier: assurez-vous que la variable env HISTCONTROL ne spécifie pas "ignorespace" (ou "ignoreboth").
Mais je ressens votre douleur avec plusieurs sessions simultanées. Il n'est tout simplement pas bien géré en bash.
Voici mon amélioration de @ lesmana réponse . La principale différence est que les fenêtres simultanées ne partagent pas l'historique. Cela signifie que vous pouvez continuer à travailler dans vos fenêtres, sans que le contexte des autres fenêtres ne soit chargé dans vos fenêtres actuelles.
Si vous tapez explicitement "historique", OR si vous ouvrez une nouvelle fenêtre, vous obtenez l'historique de toutes les fenêtres précédentes.
De plus, j'utilise cette stratégie pour archiver chaque commande jamais tapée sur ma machine.
# Consistent and forever bash history
HISTSIZE=100000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups
_bash_history_sync() {
builtin history -a #1
HISTFILESIZE=$HISTSIZE #2
}
_bash_history_sync_and_reload() {
builtin history -a #1
HISTFILESIZE=$HISTSIZE #2
builtin history -c #3
builtin history -r #4
}
history() { #5
_bash_history_sync_and_reload
builtin history "$@"
}
export HISTTIMEFORMAT="%y/%m/%d %H:%M:%S "
Prompt_COMMAND='history 1 >> ${HOME}/.bash_eternal_history'
Prompt_COMMAND=_bash_history_sync;$Prompt_COMMAND
J'ai choisi de mettre l'historique dans un fichier par tty, car plusieurs personnes peuvent travailler sur le même serveur - la séparation des commandes de chaque session facilite l'audit.
# Convert /dev/nnn/X or /dev/nnnX to "nnnX"
HISTSUFFIX=`tty | sed 's/\///g;s/^dev//g'`
# History file is now .bash_history_pts0
HISTFILE=".bash_history_$HISTSUFFIX"
HISTTIMEFORMAT="%y-%m-%d %H:%M:%S "
HISTCONTROL=ignoredups:ignorespace
shopt -s histappend
HISTSIZE=1000
HISTFILESIZE=5000
L'histoire ressemble maintenant à:
user@Host:~# test 123
user@Host:~# test 5451
user@Host:~# history
1 15-08-11 10:09:58 test 123
2 15-08-11 10:10:00 test 5451
3 15-08-11 10:10:02 history
Avec les fichiers ressemblant à:
user@Host:~# ls -la .bash*
-rw------- 1 root root 4275 Aug 11 09:42 .bash_history_pts0
-rw------- 1 root root 75 Aug 11 09:49 .bash_history_pts1
-rw-r--r-- 1 root root 3120 Aug 11 10:09 .bashrc
Ici, je soulignerai un problème avec
export Prompt_COMMAND="${Prompt_COMMAND:+$Prompt_COMMAND$'\n'}history -a; history -c; history -r"
et
Prompt_COMMAND="$Prompt_COMMAND;history -a; history -n"
Si vous exécutez source ~/.bashrc, $ Prompt_COMMAND sera comme
"history -a; history -c; history -r history -a; history -c; history -r"
et
"history -a; history -n history -a; history -n"
Cette répétition se produit chaque fois que vous exécutez "source ~/.bashrc". Vous pouvez vérifier Prompt_COMMAND après chaque exécution de "source ~/.bashrc" en exécutant "echo $ Prompt_COMMAND".
Vous pouvez voir que certaines commandes sont apparemment cassées: "history -n history -a". Mais la bonne nouvelle est que cela fonctionne toujours, car d'autres parties forment toujours une séquence de commandes valide (impliquant simplement des frais supplémentaires en raison de l'exécution répétée de certaines commandes. Et pas si propre.)
Personnellement, j'utilise la version simple suivante:
shopt -s histappend
Prompt_COMMAND="history -a; history -c; history -r"
qui a la plupart des fonctionnalités sans problème tel que mentionné ci-dessus.
Un autre point à souligner est: il n'y a vraiment rien de magique . Prompt_COMMAND est juste une variable d'environnement bash simple. Les commandes qu'il contient sont exécutées avant d'obtenir l'invite bash (le signe $). Par exemple, votre Prompt_COMMAND est "echo 123" et vous exécutez "ls" dans votre terminal. L'effet est comme exécuter "ls; echo 123".
$ Prompt_COMMAND="echo 123"
sortie (tout comme l'exécution de 'Prompt_COMMAND = "echo 123"; $ Prompt_COMMAND'):
123
Exécutez ce qui suit:
$ echo 3
production:
3
123
"history -a" est utilisé pour écrire les commandes d'historique en mémoire dans ~/.bash_history
"history -c" est utilisé pour effacer les commandes d'historique en mémoire
"history -r" est utilisé pour lire les commandes d'historique de ~/.bash_history dans la mémoire
Voir l'explication de la commande d'historique ici: http://ss64.com/bash/history.html
PS: Comme d'autres utilisateurs l'ont souligné, l'exportation n'est pas nécessaire. Voir: en utilisant l'exportation dans .bashrc
J'ai écrit un script pour définir un fichier d'historique par session ou tâche en fonction des éléments suivants.
# write existing history to the old file
history -a
# set new historyfile
export HISTFILE="$1"
export HISET=$1
# touch the new file to make sure it exists
touch $HISTFILE
# load new history file
history -r $HISTFILE
Il ne faut pas nécessairement enregistrer toutes les commandes d'historique, mais il enregistre celles qui m'intéressent et il est plus facile de les récupérer, puis de passer par chaque commande. Ma version répertorie également tous les fichiers d'historique et offre la possibilité de les parcourir tous.
Source complète: https://github.com/simotek/scripts-config/blob/master/hiset.sh
Voici une solution qui ne mélange pas les historiques des sessions individuelles!
Fondamentalement, il faut stocker l'historique de chaque session séparément et le recréer à chaque invite. Oui, il utilise plus de ressources, mais ce n'est pas aussi lent que cela puisse paraître - le retard ne commence à être perceptible que si vous avez plus de 100 000 entrées d'historique.
Voici la logique de base:
# on every Prompt, save new history to dedicated file and recreate full history
# by reading all files, always keeping history from current session on top.
update_history () {
history -a ${HISTFILE}.$$
history -c
history -r
for f in `ls ${HISTFILE}.[0-9]* | grep -v "${HISTFILE}.$$\$"`; do
history -r $f
done
history -r "${HISTFILE}.$$"
}
export Prompt_COMMAND='update_history'
# merge session history into main history file on bash exit
merge_session_history () {
cat ${HISTFILE}.$$ >> $HISTFILE
rm ${HISTFILE}.$$
}
trap merge_session_history EXIT
Voir cet Gist pour une solution complète, y compris quelques sauvegardes et optimisations de performances.
Parce que je préfère l'histoire infinie qui a été enregistrée dans un fichier personnalisé. Je crée cette configuration basée sur https://stackoverflow.com/a/19533853/4632019 :
export HISTFILESIZE=
export HISTSIZE=
export HISTTIMEFORMAT="[%F %T] "
export HISTFILE=~/.bash_myhistory
Prompt_COMMAND="history -a; history -r; $Prompt_COMMAND"
Cela fonctionne pour ZSH
##############################################################################
# History Configuration for ZSH
##############################################################################
HISTSIZE=10000 #How many lines of history to keep in memory
HISTFILE=~/.zsh_history #Where to save history to disk
SAVEHIST=10000 #Number of history entries to save to disk
#HISTDUP=erase #Erase duplicates in the history file
setopt appendhistory #Append history to the history file (no overwriting)
setopt sharehistory #Share history across terminals
setopt incappendhistory #Immediately append to the history file, not just when a term is killed
Je le voulais depuis longtemps, en particulier la possibilité de récupérer une commande par où elle était exécutée pour être réexécutée dans un nouveau projet (ou trouver un répertoire par une commande). J'ai donc mis cet outil ensemble, qui combine les solutions précédentes pour stocker un historique CLI global avec un outil interactif de grepping appelé percol (mappé sur C ^ R). Il est toujours lisse sur la première machine que j'ai commencé à utiliser, maintenant avec un historique CLI> 2 ans.
Il ne dérange pas l'historique local de la CLI en ce qui concerne les touches fléchées, mais vous permet d'accéder assez facilement à l'historique global (que vous pouvez également mapper à autre chose que C ^ R)
Voici l'extrait de mon .bashrc et de courtes explications là où c'est nécessaire:
# The following line ensures that history logs screen commands as well
shopt -s histappend
# This line makes the history file to be rewritten and reread at each bash Prompt
PROMPT_COMMAND="$Prompt_COMMAND;history -a; history -n"
# Have lots of history
HISTSIZE=100000 # remember the last 100000 commands
HISTFILESIZE=100000 # start truncating commands after 100000 lines
HISTCONTROL=ignoreboth # ignoreboth is shorthand for ignorespace and ignoredups
Le HISTFILESIZE et le HISTSIZE sont des préférences personnelles et vous pouvez les modifier selon vos goûts.