web-dev-qa-db-fra.com

Supprimer les N dernières lignes de l'historique bash

Lorsque vous collez accidentellement un fichier dans le shell, cela met une tonne d'entrées non-sens laides dans l'historique de bash. Existe-t-il un moyen propre de supprimer ces entrées? Évidemment, je pouvais fermer le Shell et éditer le .bash_history fichier manuellement mais peut-être existe-t-il une sorte d'API disponible pour modifier l'historique du shell actuel?

43
ThiefMaster

À partir du bash-5.0-alpha, la commande history prend désormais une plage pour la suppression (-d). Voir réponse de rastafile .

Pour les anciennes versions, solution de contournement ci-dessous.


Vous pouvez utiliser history -d offset intégré pour supprimer une ligne spécifique de l'historique du Shell actuel, ou history -c pour effacer toute l'histoire.

Ce n'est pas vraiment pratique si vous voulez supprimer une plage de lignes, car cela ne prend qu'un seul décalage comme argument, mais vous pouvez l'encapsuler dans une fonction avec une boucle.

rmhist() {
    start=$1
    end=$2
    count=$(( end - start ))
    while [ $count -ge 0 ] ; do
        history -d $start
        ((count--))
    done
}

Appelez-le avec rmhist first_line_to_delete last_line_to_delete. (Numéros de ligne en fonction de la sortie de history.)

(Utilisation history -w pour forcer l'écriture dans le fichier historique.)

36
Mat

Juste cette doublure dans l'invite de commande vous aidera.

for i in {1..N}; do history -d START_NUM; done

Où START_NUM est la position de départ de l'entrée dans l'historique. N est le nombre d'entrées que vous souhaitez supprimer.

ex: for i in {1..50}; do history -d 1030; done

32
user2982704

La commande intégrée history bash prend également une plage, maintenant en 2020:

-d offset

Supprimez l'entrée d'historique au décalage de position. Si l'offset est négatif, il est interprété comme relatif à un supérieur à la dernière position d'historique, de sorte que les indices négatifs comptent à rebours à partir de la fin de l'historique, et un indice de -1 fait référence à la commande history -d actuelle.

- d début-fin

Supprimez les entrées d'historique entre les positions de début et de fin, inclus. Les valeurs positives et négatives pour le début et la fin sont interprétées comme décrit ci-dessus.

Seule la commande elle-même ne le dit pas avec --help:

 Options:
   -c        clear the history list by deleting all of the entries
   -d offset delete the history entry at position OFFSET. Negative
             offsets count back from the end of the history list

   -a        append history lines from this session to the history file
   ...

Par exemple. history -d 2031-2034 supprime quatre lignes à la fois. Vous pouvez utiliser $HISTCMD pour supprimer des N lignes les plus récentes vers l'arrière.


Vous pouvez également exporter avec history -w tmpfile, puis modifiez ce fichier, effacez avec history -c puis relire avec history -r tmpfile. Pas d'écriture dans . Bash_history .

3
rastafile

Si vous supprimez la ligne N de l'historique, la ligne N+1 se déplace en position N etc.

Pour cette raison, je préfère identifier la ligne d'historique oldest et newest entre laquelle je souhaite supprimer tout l'historique. (Remarque: oldest <newest).

Si, par exemple, je souhaite supprimer les lignes d'historique de oldest = 123 Jusqu'à newest = 135, J'écrirais:

$ for i in {135..123}; do history -d $i ; done

Je trouve cela plus facile à lire; en plus: la commande for peut aussi décrémenter une plage ...

1
ShutterFreak

Cela devrait supprimer chaque entrée de la liste d'historique dans l'ordre inverse N fois:

function hd { for i in $(seq 1 $1); do history -d $(($HISTCMD-1)); done; }

Si vous souhaitez ajouter ceci à votre .bashrc, utilisez:

echo "function hd { for i in $(seq 1 $1); do history -d \$((\$HISTCMD-1)); done; }">>~/.bashrc

..et alors source ~/.bashrc pour recharger la configuration bash. Utilisé comme:

hd <N>, where N is the number of lines to delete

Voir mon autre réponse pour une approche différente qui ne fonctionne pas, mais qui est longue et compliquée.

0
alchemy

La réponse de user2982704 a presque fonctionné pour moi mais pas tout à fait. J'ai dû faire une petite variation comme ça.

En supposant que mon historique est à 1000 et que je souhaite supprimer les 50 dernières entrées

start=1000

for i in {1..50}; do count=$((start-i)); history -d $count; done
0
aberpaul

Avant d'abandonner cette approche alternative, je veux mettre de côté ce que j'ai appris. Une partie de ma difficulté à déboguer ma première réponse est que son nombre de N finit par ne pas être clair, car il inclut la commande actuelle, donc je pense que c'est vraiment N-1 ou peut-être N-2.

Pour être plus clair, j'essayais une solution qui supprimerait d'un numéro de ligne à l'avenir. Et wow, quelle grande surprise de la difficulté. Le problème principal est que la routine d'historique s'exécute en arrière-plan, donc la suppression du numéro 50 entraînera le numéro 51 à 50 en moins d'une seconde. J'ai donc essayé de créer une fonction pour supprimer en remontant à la fin. Et lorsque vous essayez de supprimer 10 d'affilée, il obtient environ 5 avant de manquer de commandes lorsqu'elles diminuent. J'ai donc essayé de créer une fonction pour supprimer vers l'avant et pour une raison quelconque, elle n'en obtient qu'une autre. Conformément à la routine d'historique exécutée environ la moitié de la vitesse de la fonction. J'ai également essayé d'insérer le sommeil à certains moments.

J'ai essayé de désactiver temporairement l'historique, mais $ HISTCMD affiche le total de $ HISTFILE et non la liste d'historique. Cela ne semble donc pas possible. Mon objectif était de nettoyer l'historique des commandes inutiles afin que je puisse mémoriser le numéro de bang! # Et utiliser les mêmes à l'avenir pour les commandes fréquentes et difficiles.

Voici quelques-unes des fonctions que j'ai essayées. Peut-être que quelqu'un peut améliorer ou diagnostiquer:

Going from the Number to the end:
function hd2 { a=$HISTCMD; echo $a; echo $1; echo $(($a%$1)); for i in $(seq $1 $a); do echo $i; history -d $i; done; }

Deleting from the end repeatedly with sleep:
function hd3 { a=$HISTCMD; echo $a; echo $1; echo $(($a%$1)); for i in $(seq 1 $a); do history -d $HISTCMD; sleep 1; done; }

Deleting the Number repeatedly with sleep:
function hd4 { a=$HISTCMD; echo $a; echo $1; echo $(($a%$1)); for i in $(seq 1 $a); do history -d $1; sleep 1; done; }

La variable d'écho de début sert au débogage. % est le reste ou le mod. $ HISTCMD n'effectue pas de substitution de commande et doit être affecté en tant que variable.

nouvelle idée: puisque la fonction ci-dessous fonctionne avec une utilisation répétée:

echo "function hdn { history -d \$1; }">>~/.bashrc

echo "function hdn2 { for i in $(seq 1 \$2); history -d \$1; sleep 1; done; }">>~/.bashrc
0
alchemy

J'ai essayé avec la commande ci-dessous et cela a bien fonctionné

 end=`history| awk 'END{print $1}'`
    start=`history| awk 'END{print $1-10}'`

    awk -v end="$end" -v start="$start"  '{for(i=start;i<=end;i++){print "history -d" " " i};exit}’|sh
0
Praveen Kumar BS