They say that those who don’t know history are doomed to repeat it —
but if you don’t know how to use your history in Bash, you’re just not
making the most of your system. But this is simple to overcome with
five tips on working with history on GNU Bash.
Most users are aware that they can access the history by using the history command, or just scroll through the history using the arrow keys or Ctrl-p (previous) or Ctrl-n (next). That, in and of itself, is really useful. But you’re not making full use of the Bash history. Let’s look at a few less-used tricks for making use (or not) of Bash’s history command and features.
By the Numbers
When you run history you see a list of the commands that have been run (as long as they’ve been logged — more on that in a second) and a number to the left of the command.
You can re-run a command by using !n where n is the number of a command. So !50 will run the 50th command in the history. Or you can run a command by using !-n where that’s the current command minus n. More clearly — !-3 will run the third-last command in your history. If the output of history looks like this:
1 sudo su
3 sudo apt-get update
Then running !-3 would run sudo su.
A Little Twist
How many times have you run a command and then realized, I meant to use sudo in front of that!? I do it all the time. One way to recover would be simply to scroll back in your history (up arrow, or Ctrl-p and then hit Ctrl-a to move to the front of the line and then type sudo. Another, even easier, way, is to do this:
That will run the last command (!!) with sudo. Nice, eh?
You probably already know that !command will run the most recent command that begins with “command. So if you’ve recently run a really long command string, all you really need to do in order to repeat it is to run !command.
But did you know that Bash wasn’t looking for a command, it’s looking for a string? That means it’s looking for a match to the characters, not a match to the full command. Let’s say your last command using git was something like this:
git commit -a -m “Various and sundry notes”
Most users will type !git to run the command — but all you really need to type is !gi or even !g if no other commands are going to match the leading string.
Now, what if you’ve run a lot of commands but wanted to match based on the second string in the command — the command that you used with git instead? Then you could use !?command? and the history built-in would match “command” in the string.
Another tiny tip, use Esc-. (that’s Escape and period) to get the last word (string) to a command. Hit it once and you’ll get the word for the last command. Hit it again, and you’ll get the last word for the command before that. For example, if you run cp filename1 filename2 hitting Esc-. will add filename2 at the cursor. Try it and see how it works — it’s very useful.
But what if you want, say, the third word? Or all of the words? For example, if you’ve run this:
ls file1.txt file2.txt file3.txt file4.txt
You might want to quickly just get the middle two filenames. You can do that by running:
If you want all the arguments/words passed to a command without the command itself, run:
Another useful, perhaps most useful, trick is to use Ctrl-r to search through the history for a command that matches a search string.
For instance, run Ctrl-r and type “hi” — it will bring up the first command with “hi” in the string (such as history). Hit Ctrl-r again, and it will bring up the second most recent command, and so on. When you find the command you want, then just hit Enter and it will run again.
If you want to modify the command, hit the right or left arrow and then Bash will leave you at the prompt with the command to edit it before running the command.
Privacy and Security
The Bash history is really useful, but there may be times when you don’t want to save commands to your history. For instance, if you’re using a shared machine you may not want your command history to be visible to the system’s administrators — who could just log in as root and read your ~/.bash_history. If it’s not a shared machine, there’s always a chance the system could be compromised — so if you’re doing anything you want to keep really private, then you might want to exercise some controls. Finally, you might just want to keep from logging certain commands because it’s just not useful to have them clogging up your history. You might use ls all the time, but why retain something like that when it’s more useful to keep longer commands that are a pain to type?
Let’s take a look at ways to keep commands from being saved in history, whatever the reason.
One way to do this is to set HISTCONTROL=ignorespace:ignoredups in your .bashrc. The ignoredups does what it sounds like — it won’t log duplicates to your history, so if you run ls twice in a row, or something like that, it won’t be saved more than once.
The ignorespace works like this: Type a space before a command, and it won’t be logged to your history. So if you want to run a super-secret command, start it off with a space.
Some distros add this by default, but you can add it yourself by adding the line above to your .bashrc.
You could also use the HISTIGNORE environment variable to tell Bash to ignore certain commands or parameters. Let’s say you don’t want to log any commands that have the name of a private server. You can set HISTIGNORE=”*myserver*” and then use the name with impunity.
Well, sort-of impunity. The usual caveats apply &mdas; if you’re on a shared server, there may be ways for other users to see what’s in memory or use ps aux or something to see what commands are being run. So, these measures are useful — but may not be 100% bulletproof. Don’t do really sensitive work on machines that you don’t trust, mmkay?
I hope that this has provided a few tips that you will find useful. But it’s not everything you can do — be sure to check out the man page for history to learn more.