214

Commands follows

  511  clear
  512  history
  513  history -d 505
  514  history
  515  history -d 507 510 513
  516  history
  517  history -d 509
  518  history
  519  history -d 511
  520  history

I can delete single one by history -d 511, but how to delete last 10 commands and in between 10 commands history using single command in shell?

Can we write a bash script and execute for deletion of history?

9
  • 27
    vi $HISTFILE and delete what you want. Use head -n -10 if you have to automate it. Commented Feb 7, 2013 at 12:07
  • Is this question off-topic? or This is not wright place to ask this kind of question? If so, where should I ask this question, I mean where in stack exchange? Commented Feb 7, 2013 at 12:14
  • 1
    Shell commands work the same whether you're logged in locally or via ssh.
    – Barmar
    Commented Feb 7, 2013 at 12:19
  • 3
    Unix and Linux StackExchange (unix.stackexchange.com) is probably a better venue for this question. It's off-topic here because it doesn't relate strictly to programming. Commented Feb 7, 2013 at 12:32
  • 6
    Programming a shell script is the ideal solution to this question, consequently it should be considered related to programming. Not to mention the fact that the OP actually asked specifically for a script.
    – SSH This
    Commented Jan 22, 2014 at 2:26

22 Answers 22

151

Have you tried editing the history file directly:

~/.bash_history
10
  • 20
    will take effect after relaunching (closing and re-opening) the terminal Commented Dec 11, 2014 at 10:13
  • 9
    If you do this with vim you may find your deletion history in ~/.viminfo so be sure to remove that too!
    – waltwood
    Commented Jul 22, 2015 at 22:39
  • 5
    sometimes it's kept in memory and any manual editing wont be persisted after next login..
    – superhero
    Commented Sep 15, 2016 at 8:39
  • 4
    @FizerKhan that wont help the fact that it's kept in memory. It's the history file that is kept in memory sometimes, so even if you edit the file it wont take effect..
    – superhero
    Commented Nov 29, 2016 at 9:47
  • 7
    @FizerKhan I mean that changes made in .bash_history can be overwritten by what is kept in memory. I found this solution helpful: superuser.com/a/384383/253543
    – superhero
    Commented Nov 29, 2016 at 10:42
136

My answer is based on previous answers, but with the addition of reversing the sequence so that history items are deleted from most recent to least recent.

Get your current history (adjust the number of lines you want to see):

history | tail -n 10

This gives me something like

1003  25-04-2016 17:54:52 echo "Command 1"
1004  25-04-2016 17:54:54 echo "Command 2"
1005  25-04-2016 17:54:57 echo "Command 3"
1006  25-04-2016 17:54:59 echo "Command 4"
1007  25-04-2016 17:55:01 echo "Command 5"
1008  25-04-2016 17:55:03 echo "Command 6"
1009  25-04-2016 17:55:07 echo "Command 7"
1010  25-04-2016 17:55:09 echo "Command 8"
1011  25-04-2016 17:55:11 echo "Command 9"
1012  25-04-2016 17:55:14 echo "Command 10"

Select the start and end positions for the items you want to delete. I'm going to delete entries 1006 to 1008.

for h in $(seq 1006 1008); do history -d 1006; done

This will generate history -d commands for 1006, then 1007 becomes 1006 and 1006 is deleted, then 1008 (became 1007) is now 1006 and gets deleted.

If I also wanted to delete the history delete command then it's a bit more complicated because you need to know the current max history entry.

You can get this with (there may be a better way):

history 1 | awk '{print $1}'

Putting it together you can use this to delete a range, and also delete the history delete command:

for h in $(seq 1006 1008); do history -d 1006; done; history -d $(history 1 | awk '{print $1}')

Wrap this all up in a function to add to your ~/.bashrc:

histdel(){
  for h in $(seq $1 $2); do
    history -d $1
  done
  history -d $(history 1 | awk '{print $1}')
  }

Example deleting command 4, 5 and 6 (1049-1051) and hiding the evidence:

[18:21:02 jonathag@gb-slo-svb-0221 ~]$ history 11
 1046  25-04-2016 18:20:47 echo "Command 1"
 1047  25-04-2016 18:20:48 echo "Command 2"
 1048  25-04-2016 18:20:50 echo "Command 3"
 1049  25-04-2016 18:20:51 echo "Command 4"
 1050  25-04-2016 18:20:53 echo "Command 5"
 1051  25-04-2016 18:20:54 echo "Command 6"
 1052  25-04-2016 18:20:56 echo "Command 7"
 1053  25-04-2016 18:20:57 echo "Command 8"
 1054  25-04-2016 18:21:00 echo "Command 9"
 1055  25-04-2016 18:21:02 echo "Command 10"
 1056  25-04-2016 18:21:07 history 11
[18:21:07 jonathag@gb-slo-svb-0221 ~]$ histdel 1049 1051
[18:21:23 jonathag@gb-slo-svb-0221 ~]$ history 8
 1046  25-04-2016 18:20:47 echo "Command 1"
 1047  25-04-2016 18:20:48 echo "Command 2"
 1048  25-04-2016 18:20:50 echo "Command 3"
 1049  25-04-2016 18:20:56 echo "Command 7"
 1050  25-04-2016 18:20:57 echo "Command 8"
 1051  25-04-2016 18:21:00 echo "Command 9"
 1052  25-04-2016 18:21:02 echo "Command 10"
 1053  25-04-2016 18:21:07 history 11

The question was actually to delete the last 10 commands from history, so if you want to save a little effort you could use another function to call the histdel function which does the calculations for you.

histdeln(){

  # Get the current history number
  n=$(history 1 | awk '{print $1}')

  # Call histdel with the appropriate range
  histdel $(( $n - $1 )) $(( $n - 1 ))
  }

This function takes 1 argument, the number of previous history items to delete. So to delete the last 10 commands from history just use histdeln 10.

8
  • history | tail -1 | awk '{print $1}' can be simplified to history 1 | awk '{print $1}' Commented Aug 20, 2018 at 18:49
  • -bash: tac: command not found on Mac OSX, otherwise this would be the best answer.
    – Zim
    Commented Jan 24, 2020 at 17:38
  • for h in $(seq 1006 1008); do history -d 1006; done this works in ubuntu 16.04
    – mahfuz
    Commented May 22, 2020 at 17:54
  • 1
    Short but sweet: for i in {1..10}; do history -d $(($HISTCMD-11)); done
    – alchemy
    Commented Jun 3, 2020 at 14:38
  • 1
    @alchemy replace the '11' with 'i' and then yes, this works perfectly!
    – E. Körner
    Commented Jul 9, 2021 at 14:05
100

With Bash 5 you can now do a range...Hooray!:

history -d 511-520

or counting backwards 10:

history -d -10--1

Excerpt from Bash 5 Man Page:

'history'

Options, if supplied, have the following meanings:

'-d OFFSET' Delete the history entry at position OFFSET. If OFFSET is positive, it should be specified as it appears when the history is displayed. 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.

Here is my solution for Bash 4. It iteratively deletes a single entry or a range of history starting with lowest index.

delHistory () {
    count=$(( ${2:-$1} - $1 ))
    while [[ $count -ge 0 ]]; do
        history -d "$1"
        ((count--))
    done
}

delHistory 511 520
1
  • 3
    this was working, but now I get "bash: history: -10: history position out of range"..I even get that error with history -d -2.. I wonder why. This worked for me.. it deletes the last entry hdl() { history -d $(($HISTCMD - $1))-$(($HISTCMD - 2)) ;} unix.stackexchange.com/a/573258/346155
    – alchemy
    Commented Mar 18, 2022 at 20:58
31
for x in `seq $1 $2`
do
  history -d $1
done
4
  • 3
    Be sure to use the higher number for the first argument or you will delete every other command. E.g. when command 511 is deleted, everything shifts down so 512 becomes the new 511 and 513 is the new 512. Therefor history -d 511 works as expected, then history -d 512 deletes what used to be 513, and 512 remains in the history as command 511. Hope that makes sense.
    – Matthew
    Commented Dec 8, 2015 at 21:12
  • 6
    @Matthew That's not necessary. I'm not deleting $x each time through the loop, I'm deleting $1. So it first deletes 511,and 512 becomes 511. Then it deletes 511 again, and so on.
    – Barmar
    Commented Dec 8, 2015 at 21:37
  • @Matthew Notice that I made a similar comment to Tyler's answer. I came up with my solution as a fix for that.
    – Barmar
    Commented Dec 8, 2015 at 21:38
  • 1
    you are correct, in my haste when wrote this out in a single line in my bash prompt I used for i in ... and history -d $i and got the results I described in my comment above. Using $1 this absolutely is correct as stated in your original answer.
    – Matthew
    Commented Dec 8, 2015 at 23:46
27

First, type: history and write down the sequence of line numbers you want to remove.

To clear lines from let's say line 1800 to 1815 write the following in terminal:

$ for line in $(seq 1800 1815) ; do history -d 1800; done

If you want to delete the history for the deletion command, add +1 for 1815 = 1816 and history for that sequence + the deletion command will be deleted.

For example :

$ for line in $(seq 1800 1816) ; do history -d 1800; done
2
  • I made an update but still not working correctly in Ubuntu 12.04.. :( It looks like the line number part is not working correctly Commented Apr 13, 2016 at 9:23
  • I rejected Binod's suggested edit as it's not a logical error. Ghassan's original code uses the same approach as Barmar's answer – which works. The comments to Barmar's answer explain why the suggestion of replacing 1800 with $line deletes every other line and then exceeds the desired range. Commented Apr 13, 2016 at 9:37
22

Combining answers from above:

history -w vi ~/.bash_history history -r

0
11

I used a combination of solutions shared in this thread to erase the trace in commands history. First, I verified where is saved commands history with:

echo $HISTFILE

I edited the history with:

vi <pathToFile>

After that, I flush current session history buffer with:

history -r && exit

Next time you enter to this session, the last command that you will see on command history is the last that you left on pathToFile.

1
  • this works for me , for the answer from @jgc , when i login again to server , history is back again , works only for that logged in session Commented Feb 17, 2020 at 19:41
10

Maybe will be useful for someone.
When you login to any user of any console/terminal history of your current session exists only in some "buffer" which flushes to ~/.bash_history on your logout.
So, to keep things secret you can just:
history -r && exit
and you will be logged out with all your session's (and only) history cleared ;)

9

edit:

Changed the braced iterators, good call. Also, call this function with a reverse iterator.

You can probably do something like this:

#!/bin/bash
HISTFILE=~/.bash_history   # if you are running it in a 
                           # non interactive shell history would not work else
set -o history
for i in `seq $1 $2`;
do
    history -d $i
done
history -w

Where you will evoke like this:

./nameOfYourScript 563 514

Notice I haven't put any error checking in for the bounds. I'll leave that as an exercise to the reader.

see also this question

3
  • 6
    After you delete 510, 511 becomes 510, 512 becomes 511, and so on. So this will delete every other line.
    – Barmar
    Commented Feb 7, 2013 at 12:12
  • You cannot include variables in brace expansions.
    – chepner
    Commented Feb 7, 2013 at 18:10
  • seq 563 514 will print nothing. You need seq 563 -1 514. Alternately, you can simply use history -d $1 with arguments as 514 563
    – anishsane
    Commented Aug 21, 2015 at 4:43
7

Not directly the requested answer, but maybe the root-cause of the question:

You can also prevent commands from even getting into the history, by prefixing them with a space character:

# This command will be in the history
echo Hello world

# This will not
 echo Hello world
2
  • This is not working for me
    – Loenix
    Commented May 25, 2022 at 7:42
  • @Leonix maybe it depends on the shell you use? Did you try it according to these docs: linux-training.be/funhtml/ch16.html ("prevent recording a command")? Commented Jun 6, 2022 at 7:45
3

to delete last 10 entries (based on your example) :

history -d 511 520
2
  • 2
    In GNU bash, version 4.3.11(1) this only deletes the first line in the list
    – Gary
    Commented Jun 12, 2018 at 16:42
  • You need a dash between the 2 numbers (no space) to delete the range. Commented Oct 8, 2021 at 14:10
3
history -d 511;history -d 511;history -d 511;history -d 511;history -d 511;history -d 511;history -d 511;history -d 511;history -d 511;history -d 511;

Brute but functional

2

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

1
for h in $(seq $(history | tail -1 | awk '{print $1-N}')  $(history | tail -1 | awk '{print $1}') | tac); do history -d $h; done; history -d $(history | tail -1 | awk '{print $1}')

If you want to delete 10 lines then just change the value of N to 10.

1

I use this script to delete last 10 commands in history:

pos=$HISTCMD; start=$(( $pos-11 )); end=$(( $pos-1 )); for i in $(eval echo "{${start}..${end}}"); do history -d $start; done

It uses $HISTCMD environment var to get the history index and uses that to delete last 10 entries in history.

1

I use this (I have bash 4):

histrm() {
    local num=${1:- 1}
    builtin history -d $(builtin history | sed -rn '$s/^[^[:digit:]]+([[:digit:]]+)[^[:digit:]].*$/\1/p')
    (( num-- )) && $FUNCNAME $num
    builtin history -w
}

The builtin history parts as well as the last -w is because I have in place a variation of the famous tricks to share history across terminals and this function would break without those parts. They ensure a call to the real bash history builtin (and not to my own wrapper around it), and to write the history to HISTFILE right after the entries were removed.

However this will work as it is with "normal" history configurations.

You should call it with the number of last entries you want to remove, for example:

histrm 10

Will remove the last 10 entries.

1
#delete ten times the last history line    
for i in $(seq 1 10)
do
  n=$(history 1 | awk '{print $1}')
  history -d $n
done
1

history -c will clear all histories.

0
0

A simple function can kill all by number (though it barfs on errors)

kill_hist() {
    for i in $(echo $@ | sed -e 's/ /\n/g;' | sort -rn | sed -e 's/\n/ /;')
    do
            history -d $i;
    done
}
kill_hist `seq 511 520`
# or kill a few ranges
kill_hist `seq 1001 1010` `seq 1200 1201`
0

Try the following:

for i in {511..520}; do history -d $i; echo "history -d $i"; done
3
  • That assumes he has already listed the history and knows all IDs beforehand
    – Markoorn
    Commented Jan 15, 2019 at 8:19
  • and it cannot be the lastest in the history list, otherwise: "history position out of range"
    – devwebcl
    Commented Sep 24, 2019 at 13:19
  • 1
    it must be: for i in {511..520}; do history -d $i; echo "history -d 511"; done
    – devwebcl
    Commented Sep 24, 2019 at 15:25
0

the history -d arg takes a range and $HISTCMD is the max number in the history.

This function works to remove the last n entries from history (just pass in the number of history commands to remove like, eg rmhist 5) :

$ rmhist()  { history -d $(($HISTCMD - $1))-$HISTCMD ;}

Or.. Go fancy with an arg like this to remove from a point in history (inclusive) or last 'n' commands:

rmhist() { 
  case $1 in 
    --from|from) local start=$2; ;; 
    --last|last) local start=$(($HISTCMD - $2)) ;; 
    *) echo "Try rmhist --from # or rmhist --last n "; return ;; 
  esac; 
  history -d ${start}-${HISTCMD}
}

The result looks something like this:

 5778  ls /etc
 5779  ls /tmp
 5780  ls /dev
 5781  ll
 5782  cd /tmp
 5783  cd
 5784  history
(base) ~ $ rmhist --last 3
(base) ~ $ history 5
 5778  ls /etc
 5779  ls /tmp
 5780  ls /dev
 5781  ll
 5782  history 5
(base) ~ $ rmhist --from 5780
(base) ~ $ history 5
 5776  history 10
 5777  ls
 5778  ls /etc
 5779  ls /tmp
 5780  history 5
0

How to delete unwanted history entries in your shell

...or even edit or add entries.

Quick summary

# check your shell's cached history
history
# force-write the cached history to the `~/.bash_history` history file
history -w

# open the history file in your editor of choice (MS VS Code in my case)
# - THEN MANUALLY EDIT THE FILE AS NEEDED, AND SAVE IT
code ~/.bash_history

# force-read the history file into the shell's cached history
history -r

# check your shell's cached history again to ensure it worked and accepted
# your edits above
history

# As a final sanity check, view the history file one more time to ensure it
# looks as you expect. 
code ~/.bash_history

Details

I ran history and saw a command with some confidential information in it (a security key) that I don't want in my history.

So, I opened and checked the ~/.bash_history file per the main answer here, and saw that it did not match what was in my shell's history. This got me digging into the help menu to examine the -w and -r options to see what they did. A bit of experimentation later and I came up with the process above.

You might also consider using the append history -a option instead of history -w above. See the help menu I pasted below for details.

References

  1. I learned about history -w here: Unix & Linux: Why is the bash_history always coming up the same and not updating using non-login shells?
  2. See the history help menu:
    history --help
    
    Example run and output:
    $ history --help
    history: history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]
        Display or manipulate the history list.
    
        Display the history list with line numbers, prefixing each modified
        entry with a `*'.  An argument of N lists only the last N entries.
    
        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
        -n  read all history lines not already read from the history file
                and append them to the history list
        -r  read the history file and append the contents to the history
                list
        -w  write the current history to the history file
    
        -p  perform history expansion on each ARG and display the result
                without storing it in the history list
        -s  append the ARGs to the history list as a single entry
    
        If FILENAME is given, it is used as the history file.  Otherwise,
        if HISTFILE has a value, that is used, else ~/.bash_history.
    
        If the HISTTIMEFORMAT variable is set and not null, its value is used
        as a format string for strftime(3) to print the time stamp associated
        with each displayed history entry.  No time stamps are printed otherwise.
    
        Exit Status:
        Returns success unless an invalid option is given or an error occurs.
    

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