History And Aliases

History And Aliases

Consider the following command:

$ /Applications/MailSteward.app/Contents/MacOS//MailSteward 1 >& /dev/null

That’s the command for MailSteward to update it’s database with email received since it was last updated. It’s also a bitch of a command to remember. When faced with an unwieldy command, you basically have four alternatives:

  1. Memorize the command and type the thing in over and over; or
  2. Create a shell script; or
  3. Use an alias; or
  4. Use the history command.

(Okay, I know. I know. There are other alternatives.)

Typing the thing in over and over is ridiculous. Creating shell scripts is a viable solution but, in the long run, you end up with too many shell scripts. Aliases could work (and we’ll get to them shortly) but suffer from the same shortcoming as shell scripts. The history command is a perfect solution.

history is a built-in shell command and it’s availability depends on the shell you’re running. The default OS X shell is Bash which includes a history command.

As you enter commands from the command line, Bash caches them and, once you close the terminal or logout, it appends them to a file in your home directory called .bash_history. This file reflects the most recent 500 commands by default. You can change this number via the HISTSIZE environment variable, but for most people 500 is more than enough. .bash_history is just a simple text file.

$ cat ~/.bash_history ls which sh crontab -e

Interesting but not particularly useful. Now lets try the history command:

$ history 1 pwd 2 ls -ald b* 498 ls 499 which sh 500 crontab -e

Depending on how often you use the terminal, your list may be long or short. As you can see, mine has 500 entries. That’s a lot of data to sift through. How do we find something specific? How do we find that MailSteward command we entered yesterday? By piping the output through grep:

$ history | grep MailSteward 42 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 132 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 365 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 469 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null

Now that we’ve found the command we want, what do we do with it? Those numbers seem irrelevant. Who cares that the MailSteward command is the 42nd or 132nd or 365th command in our history file? We do because we can use those numbers to execute the command.

$ !42 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null $

That’s exclamation mark (!) four (4) two (2). The exclamation mark is more commonly called bang. !42 tells Bash to execute entry 42 from the history file. Once we hit enter, Bash displays and runs our command. So our workflow would look like this:

$ history | grep MailSteward 42 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 132 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 365 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 469 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null $ !42 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null $

Pretty sweet stuff, but do you really want to type *history grep MailSteward* every time you need to find that command? Of course not. So let’s talk about the alias command.

Like the history command, alias is a built-in shell command and is available in Bash. alias is used to create short-cuts or command abbreviations. Consider the following:

$ ll -bash: ll: command not found

That’s lower-case-el (l) lower-case-el (l). It’s not found because it’s not a valid command.

$ alias ll=’ls -al’ $ ll drwxr-xr-x+ 36 stephen staff 1224 Mar 2 15:23 . drwxr-xr-x 5 root admin 170 Oct 25 22:38 .. -rw-r–r–@ 1 stephen staff 24580 Mar 2 10:06 .DS_Store -rwx—— 27 stephen staff 918 Mar 1 11:46 bang-goes-boom.txt -rw——- 1 stephen staff 3 Oct 25 22:38 omg-a-file.txt

Look at that. We’ve used alias to create our own custom command. ll now executes ls -alG. ls lists directory contents. Here’s the breakdown of the parameters:

-a Include directory entries whose names begin with a dot (.). -G Enable colorized output. -l (The lowercase letter ‘el’.) List in long format.

So now you can use ls for regular directory listings and ll for long listings. Nice.

One quick word of warning: Be careful what you choose as an alias. Check this out:

alias ls=’ssh’

Now every time we enter ls the system is going to execute ssh, which is probably not what we want. The ls command is important. Pick your alias carefully. (If you accidentally do this, you can bypass the alias and get to the real ls command by entering its full path: /bin/ls. See man which for information on locating a command’s full path. Or you can simply enter alias ls=’ls’ to undo it.)

Okay, where were we?

Right. Aliases.

Unfortunately, aliases are forgotten as soon as you logout. So every time you login, you have to redefine your ll alias. Bummer. Especially if you have several. What we need is a file that gets executed every time we login and defines all our aliases. Maybe a file called aliases.

And we can do that.

Every time you open a terminal window in OS X, a file called ~/.profile gets executed. The thing is, this file may or may not exist. Open your terminal (Utilities -> Terminal) and enter the following:

$ cat $HOME/.profile

If it doesn’t exist, don’t sweat it because you can create it. The point is this: All we need is .profile to execute our aliases file and we’re good to go.

If ~/.profile does not exist, do this:

$ touch $HOME/.profile

Now, using your favorite text editor, edit .profile and add the following:

. ~/aliases

That’s dot (.) space ( ) tilde (~) slash (/).

The dot (.) space ( ) is shorthand for source or execute this file as though it was a Bash script. So we’re telling .profile to execute ~/aliases as though it was a Bash script. Awesome.

Now we just need to create our ~/aliases file. Using your favorite text editor, create ~/aliases (that’s aliases in your home directory). Add the following:

alias ll=’ls -alG’ alias ls=’ls -aG’

Save your file. Notice that we also included an alias for ls, which is a valid command. It lives in /bin. Your aliases are executed before the system starts trying to locate your command. So even though ls is a valid command, every time we execute ls from this point forward, the system will use our alias and include the -aG parameters.

Now from your terminal, enter the following and try it out:

$ . ~/aliases $ ll $ ls

Awesome. Now let’s revisit our *history grep MailSteward* command. In your aliases file, add the following (I chose hg for history grep):
alias hg=’history grep’

Save the file, source it, and try out the new alias:

$ . ~/aliases $ hg MailSteward 42 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 132 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 365 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null 469 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null $ !42 /Applications/MailSteward.app/Contents/MacOS/MailSteward 1 >& /dev/null $

That’s much better. Now we can find and execute those difficult commands much more easily.