48

When accidentally pasting a file into the shell it puts a ton of ugly nonsense entries in the bash history. Is there a clean way to remove those entries? Obviously I could close the shell and edit the .bash_history file manually but maybe there's some kind of API available to modify the history of the current shell?

38

As of bash-5.0-alpha, the history command now takes a range for the delete (-d) option. See rastafile's answer.

For older versions, workaround below.


You can use history -d offset builtin to delete a specific line from the current shell's history, or history -c to clear the whole history.

It's not really practical if you want to remove a range of lines, since it only takes one offset as an argument, but you could wrap it in a function with a loop.

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

Call it with rmhist first_line_to_delete last_line_to_delete. (Line numbers according to the output of history.)

(Use history -w to force a write to the history file.)

| improve this answer | |
  • 1
    Since the OP asked for deleting the N last lines, this script should be modified by doing something like: tot_lines=$(history | wc -l) and then repeat history -d $(( tot_lines - $1 )). – PlasmaBinturong Jan 19 '18 at 9:13
  • 2
    Instead of $(history | wc -l), there is the variable $HISTCMD that can be used. – PlasmaBinturong Jan 19 '18 at 9:58
  • @mosvy: thanks for pointing it out. Updated. – Mat Mar 19 at 4:54
36

Just this one liner in command prompt will help.

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

Where START_NUM is starting position of entry in history. N is the number of entries you may want to delete.

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

| improve this answer | |
  • 3
    I wonder why this is not a built-in function already. 'history' is a very old tool. – Petr Gladkikh Aug 1 '16 at 9:23
  • serves the purpose very well, but this command can be seen in history :) – Rajeev Akotkar Nov 26 '18 at 4:12
  • askubuntu.com/a/978276/22866 has a nice way to delete the "delete from history command" from history :-) – HanSooloo Jul 4 '19 at 6:46
  • @RajeevAkotkar If the delete command is the nth line, then using N+1 in the for loop will also help delete the command that did the deleting. – lightsong Nov 29 '19 at 2:55
8

The history bash built-in command also takes a range, now in 2020:

-d offset

Delete the history entry at position offset. If offset is negative, it is interpreted as relative to one greater than the last history position, so negative indices count back from the end of the history, and an index of -1 refers to the current history -d command.

-d start-end

Delete the history entries between positions start and end, inclusive. Positive and negative values for start and end are interpreted as described above.

Only the command itself does not tell with --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
   ...

E.g. history -d 2031-2034 deletes four lines at once. You could use $HISTCMD to delete from the newest N lines backwards.


You can also export with history -w tmpfile, then edit that file, clear with history -c and then read back with history -r tmpfile. No write to .bash_history.

| improve this answer | |
1

If you delete line N from the history, then line N+1 moves in position N etc.

For this reason, I prefer identifying the oldest and newest history line between which I want to delete all history. (Note: oldest < newest).

If for instance I want to delete the history lines from oldest = 123 up to newest = 135, I'd write:

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

I find it easier to read; besides: the for command can also decrement a range...

| improve this answer | |
0

The answer by user2982704 almost worked for me but not quite. I had to make a small variation like this.

Assuming my history is is at 1000 and I want to delete the last 50 entries

start=1000

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

Tried with below command and it worked fine

 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
| improve this answer | |
  • Will this remove entries from bash's history if you pipe it through sh?? – Jeff Schaller Mar 17 at 11:10
0

Before I give up on this alternative approach, I want to put down what I've learned. Part of my difficulty in debugging my first answer is that its a bit unclear how many N ends up being, because it includes the current command, so I think it is really N-1 or maybe N-2.

To make it more clear, I was trying a solution that would delete from a line number going forward. And wow, what a big surprise of how difficult that is. The main problem is the history routine is running in the background so deleting say number 50 will result in number 51 now being 50 in less than a second. So I tried making a function to delete going backwards from the end. And when trying to deleting 10 in a row and it gets about 5 before running out of commands as they shift down. So I tried making a function to delete forwards and it, for some reason only gets every other one. Consistent with the history routine running about half as fast as the function. I also tried inserting sleep at certain points.

I tried turning off history temporarily, but then $HISTCMD show the total from $HISTFILE not the history list. So it looks nary a possible. My goal was to clean the history of unnecessary commands so that I could memorize the bang number !# and use the same ones going forward for frequent and difficult commands.

Here's some of the functions I tried. Maybe someone can improve or diagnose:

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; }

The beginning echo variable are for debugging. % is remainder or mod. $HISTCMD does not carry through command substitution and need to be assigned as a variable.

new idea: since the function below works with repeated use:

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

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

This should delete every history list entry in reverse order N times:

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

If you want to add this to your .bashrc, use:

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

..and then source ~/.bashrc to reload bash config. Use as:

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

See my other answer for a different approach that is not working, but is long and complicated.

EDIT: For a command line form use this:

for i in {1..10}; do history -d $(($HISTCMD-11)); done

Also see this question:

https://stackoverflow.com/questions/14750650/how-to-delete-history-of-last-10-commands-in-shell

| improve this answer | |
  • This doesn't address the question of deleting lines from bash's history...? – Jeff Schaller Mar 16 at 19:46
  • @JeffSchaller, (quick to jump on that. how did you even see I had answered?) Ironically I deleted the last command I used and pasted the wrong one. Just updated, but its still a little buggy, not sure why yet. – alchemy Mar 16 at 20:04
  • Just lucky coincidence that I loaded the right page at the right time! I'll suggest that you hold on to your answer until you've worked the bugs out. Actually, since there are already answers that show functions and that show the core "answer" of history -d, I'm going to suggest that you find a different question to answer altogether. – Jeff Schaller Mar 16 at 20:31
  • wow, lucky me.. what a coincidence, seeing as you are a moderator. None of them easily adds a function with arguments in one line that can be exported to .bashrc. And please keep your suggestions to yourself. Last time I checked, this is still a free country, and one of us is being constructive. – alchemy Mar 16 at 21:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.