If you are a moderate to heavy user of the command line in Linux or OS X, you’ll eventually build up a set of custom commands and shortcuts that you’ve written that help streamline your workflow. These are known as “aliases.”
Let’s say you frequently find yourself searching your shell history for a command you used before.
To display your command history, you simply type history
in your shell, and every command you’ve typed streams by.
This is useful, of course, but most likely you want to know about a particular command you typed, so you might use shell redirection to pipe the output to another command, in this case, grep
to find lines in history that are interesting to you. In this example, we’re looking for commands we’ve typed that involved the word “projects”:
$ history | grep projects
9627 cd projects/ansible_dexter
9641 cd ~/projects/ansible_dexter
9675 cd projects/ansible_dexter
9684 cd ~/projects/sendgrid-test
9696 source /home/jim/projects/sns_python/venv/bin/activate
9707 source /home/jim/projects/sns_python/venv/bin/activate
9713 cd ~/projects/
9863 cp -r ~/projects/sendgrid-test/lib64 .
9865 cp -r ~/projects/sendgrid-test/share .
9962 cd projects
9972 cd projects/terraform-provider-aws
9979 cd projects/terraform-provider-aws
10003 cd projects/terraform-provider-aws
For me, this is something I do so frequently that I wanted to shorten that command to the minimum number of characters. I settled upon hg
for “history grep”, so I created an alias as a line in my ~/.zshrc
file: alias hg="history | grep"
The ~/.zshrc
(or ~/.bashrc
if you use bash
as your shell,) is a file that gets read every time you log in and sets up your preferred environment.
Perfect! Now, if I want to search history for commands that included a particular string, I can just type hg projects
and I will get the above output.
Well, nearly perfect…
As it happens, hg
is also a command used by the Mercurial Source Code Management system. This is not a big issue for me, as I’m a loyal Git user, but it presents an interesting dilemma:
How do I protect against command name collisions in my aliases?
You see, pretty much any alias you create has the potential to conflict with a command someone else has written, but where this gets even more complicated is when these commands are referenced from a script. Scripts should, however, only call external programs using the program’s full path, e.g.:/bin/ls
instead of just ls
A blog post by Brandon Rhodes proposes an interesting solution:
Prepend all of your custom commands and aliases with a comma. Interestingly, a comma is just a normal letter to the shell, no different than renaming your command jimoconnell_hg
, though a comma is of course much shorter.
I found this tip via the excellent ‘/r/commandline’ subreddit.
I haven’t used this technique much at all yet, so let me know what you think!