Mac OS X,  Mac OS X Server,  Mac Security,  Ubuntu,  Unix

Leveraging The Useful Yet Revisionist Bash History

Not, this article is not about 1984. Nor do I believe there is anything but a revisionist history. Instead, this article is about the history command in OS X (and *nix). The history command is a funny beast. Viewing the manual page for history in OS X nets you a whole lotta’ nothin’ because it’s just going to show you the standard BSD General Commands Manual. But there’s a lot more there than most people use. Let’s take the simplest invocation of the history command. Simply run the command with no options and you’ll get a list of your previously run bash commands:

history

This would output something that looks like the following:

1  pwd
2 ls
3 cd ~/Desktop
4 cat asciipr0n

Now, you can clear all of this out in one of a few different ways. The first is to delete the .bash_history (or the history file of whatever shell you like). This would leave you with an interesting line in the resultant history:

l rm ~/.bash_history

Probably not what you were after. Another option would be to nuke the whole history file (as I did on a host accidentally with a misconstrued variable expansion, trying to write a history into a script):

history -c

A less nuke and pave method here, would be to selectively rewrite history, by choosing a line that you’d like to remove using the -d option:

history -d 4

Three are other options for history as well, mostly dealing with substitutions, but I am clearly not the person to be writing about these given that I just took ’em the wrong direction. They are -anrwps for future reference.

Finally, since you likely want a clean screen, do clear to get a nice clean screen:

clear

Now that we’re finished discussing altering your history, let’s look at using it to make your life faster. One of my most commonly tools at the command line is to use !$. !$ in any command expands to be the last position of your last run command. Take as an example you want to check the permissions of a file on the desktop:

ls -al ~/Desktop/asciipr0n

Now let’s say you want to change the permissions of that object, just use !$ since the last command had it as that only positional parameter and viola:

chmod 700 !$

Where does this come from? Well, any time you use a ! in a command, you are doing a history substitution, or expanding that variable into some kind of event designator, which is the part in your history you’re calling up. The $ is designated as first position (which yes, is a move my daughter did at her last dance recital). !# is another of these, which calls up the whole line typed so far. For example, let’s say you have a file called cat. Well, if you run cat and then use !# (provided you’re in the working directory of said file) you’d show the contents on the screen:

cat !#

Now, view your history after running a couple of these and you’ll notice that the event designators aren’t displayed in your history. Instead, they were expanded at runtime and are therefore displayed as the expanded expression. Let’s do something a tad more complicated. Let’s echo out the contents of your line 4 command from the beginning of this article:

echo `!4`

Now, if your line 4 were the same as my line 4 you’d certainly be disappointed. You see, you lost the formatting, so it’s probably not gonna’ look that pretty. If you were on line 11 and you wanted to do that same thing, you could just run !-7 and you’d go 7 lines back:

echo `!-7`

But the output would still be all jacked. Now, let’s say you ran a command and realized that jeez you forgot to sudo first. Well, !! is here for ya’. Simply run sudo !! and it will expand your last command right after the sudo:

sudo !!

The ! designator also allows you to grab the most recent command that starts with a set of letters. for example, let’s say I wanted to output the contents of my earlier echo command, and I wanted to show just the second position there:

cat !ech:2

That’s actually not gonna’ look pretty either. But that’s aside from the point. There are other designators and even modifiers to the designators as well, which allow for substitution. But again, I’m gonna’ have to go back and review my skills with those as I wouldn’t want to have you accidentally nuking your history because you expanded -c into some expression and didn’t realize that some of these will actually leave the history command as your last run command… :-/