Unix shells like bash, csh, or ksh, record user input to a history file. This keeps a running record of terminal history and is handy for reverse lookups or quickly reentering long commands.
This also means we can edit entries in the history file or control what gets saved and when.
set +o history
Turns off recording any input in the shell for the remainder of your session.
set -o history
Turns on recording input. This lets us reactivate recording without ending our session after using the set +o history
command.
By setting HISTIFLE in .bash_profile
we can prepend a single space to our commands and they will be selectively ignored.
# in .bash_profile
# History wont record commands preceded by a space
HISTCONTROL="ignorespace"
Ex.
$ echo no trace
$ echo trace
Then if we run history | tail
we get this output:
$ history | tail
1 trace
$
Since we used a single space character before our first echo no trace
command, it's discarded and not saved. By adding a leading space to history | tail
it's also excluded from our log.
If we want to remove something specific from history
we can use this:
history [-d num]
This invocation will let us pass a line number from history
and have it removed. For example if we wanted to delete the echo no trace
entry from our history output below:
$ history | tail
553 echo trace
554 echo trace
555 echo trace
556 echo trace
557 echo trace
558 echo trace
559 echo trace
560 echo trace
561 echo no trace
562 history | tail
$
We pass the line number of the command we want removed to history -d
(in this case 561) and if we look at history | tail
one more time it's deleted.
$ history -d 561
$ history | tail
554 echo trace
555 echo trace
556 echo trace
557 echo trace
558 echo trace
559 echo trace
560 echo trace
561 history | tail
562 history -d 561
563 history | tail
$
Now we can see echo no trace
is removed from history.
Expanding on history [-d num]
it's also possible to delete the last ran
command from history
after setting HISTCONTROL
, like so:
$ history -d $((HISTCMD-1))
(Note the leading space!) If that space wasn't there, this command would simply
delete itself! This command works because of HISTFILE="ignorespace"
.
Can we delete multile entries with one line? Absolutely!
$ for i in {579..574}; do history -d $i; done
Again we're using a leading space here. This loops though history
and deletes
entries in the specified range. Let's see what that looks like.
Here is our history before the running the above command:
$ history | tail
570 ls
571 cd berkley/
572 ls
573 vim package.json
574 ls
575 cd ..
576 ls
577 cd ~
578 clear
579 echo trace
$
And here's what we get after using our loop with history [-d num]
$ for i in {579..574}; do history -d $i; done
$ history | tail
565 history | tail
566 bash
567 man history
568 man bash
569 cd src
570 ls
571 cd berkley/
572 ls
573 vim package.json
574 history | tail
$
Notice how the range includes both line 579 and 574, so both echo no trace
and
ls
respectively are each removed. Awesome.
There's also a command for that.
$ history -w
This is useful if you only want the commands ran during your current session to be saved. It's key to understand that this overwrites the entire history file with only the commands ran during the current session.
In some cases you may want to prevent extremely sensitive information from ever being written to disk at all.
In which case we can force exit our current session without saving history.
$ kill -9 $$
In theory data deleted from non-volatile media can still be recovered through
forensic analysis (think commands that have been saved after a session into
history
or a HISTFILE
edited with history [-d num]
). For extra security this discards all the commands from the
previous session, preventing them from ever being written to disk.
⬆ (up arrow) Cycles through previous commands. We can use this to find a particular command we want removed. When we've reached the entry we want removed we can use a line editing keystroke like Ctrl+w and then cycle back down using ⬇ (down arrow) until we reach a new line—Finally then we can hit Enter. A removed entry will then be marked by an asterisk.
$ history | tail
491 man history
492 man bash
493 cd src
494 ls
495 cd berkley/
496 ls
497 vim package.json
498 history | tail
499 bash
500*
$
This technique also works with Ctrl+u
For when you need to start over.
history -c
Feel free to shoot me an email or message me on twitter. I'll add whatever you think I missed.
Cheers!