Saturday, November 3, 2007

bash aliases

Bash aliases are such lovely things, so I thought I would share some of my favorites and maybe even get some feedback.

Most of my aliases are there to make software development more enjoyable and less time consuming. As such, most of them deal with the projects I have in my project directories. Here are some of the more interesting ones:

for bigdir in $(ls ~/Developer/Projects/ | cut -d' ' -f7)
for dir in $(ls ~/Developer/Projects/$bigdir)
alias cd$dir="cd ~/Developer/Projects/$bigdir/$dir"
alias m$dir="cd$dir && mate ."
alias s$dir="cd$dir && ss"
alias g$dir="~/bin/svngrowl $dir"
alias o$dir="osascript -e 'tell application \"Terminal\"'
-e 'tell application \"System Events\"'
-e 'tell process \"Terminal\" to keystroke \"t\" using command down'
-e 'tell process \"Terminal\" to keystroke \"t\" using command down'
-e 'end tell'
-e 'do script \"s$dir\" in first tab of front window'
-e 'do script \"m$dir\" in second tab of front window'
-e 'do script \"g$dir\" in third tab of front window'
-e 'do script \"localhost\" in second tab of front window'
-e 'tell second tab of front window to set selected to true'
-e 'end tell'"

alias localhost="open http://localhost:3000"
alias addall="svn st | grep ? | cut -d' ' -f7 | xargs svn add"
alias removeall="svn st | grep ? | cut -d' ' -f7 | xargs rm -Rf"

for var in "server" "generate" "console" "destroy" "plugin"
alias s${var:0:1}="script/$var"

The first for loop is probably the most useful set of aliases that I have. It starts off by going through all the projects that live in my various project directories. Then, for each project it gives me a cdproject, mproject, sproject, gproject (very special), and oproject (less special, but still useful).

  • cd's into the project directory

  • opens the project in TextMate

  • starts a server for the project by calling script/server (which is what the alias ss does in a rails project)

  • starts an svngrowl process for the project (which I'll explain later)

  • Uses the command line osascript, which invokes applescript, to manipulate Terminal and Firefox

First, an explanation of what oproject is doing. To start, for viewing purposes above I cut the oproject alias into more manageable pieces, but when used should be on one line (as would be the case if it were called from the command line).

This alias is kind of like the Ring of Power, in that it rules all the other aliases, and in the darkness (or the light) binds them... into one convenient call. It opens Terminal, and opens 2 new tabs for a total of 3 tabs (only for Leopard users though :-). It then opens a server in the first tab, opens the project in TextMate in the second tab, starts an svngrowl process in the third tab, goes back to the second tab and runs the alias localhost, and then gives focus back to the second tab (since it seemed to lose focus to the third tab, not sure why). This alias is a huge time saver when you think that every working day I spend about 10 to 15 seconds when I have to open everything up (which adds up to a lot when you have enough work to do!).

As for the gproject alias, this uses a cool little script in my ~/bin directory that starts a loop for the specified project, and every 3 minutes it runs svn up on the project and if there are any changes to the project, it sends out a pretty little growl notification with what was changed, who changed it, the commit message, and if any migrations were committed it changes the priority of the message to high (which for my personal growl settings turns the message text red).

Two scripts are involved in the growling, one bash script, and a ruby script (which is invoked by the bash script). First, the bash script (cut in half for easy viewing):

source ~/.profile
alias | grep cd$@= | awk "{gsub(/cd$@='cd |'/, \"\"); print}" |
awk "{gsub(/~/, \"/Users/`whoami`\"); print}" | xargs ~/bin/svngrowl.rb

And now the ruby script:

#!/usr/bin/env ruby
directory = ARGV[0]
project = directory.split("/").last
ignore = directory.gsub(project, "")

loop do
updates = `svn up #{directory}`.gsub(ignore, "").split("\n")
last_log = `svn log #{directory} --limit 1`

revision = updates.pop.scan(/\d+/)
committer = last_log.split("\n")[1].split(" | ")[1]
priority = updates.join("\n").include?("db/migrate") ? 1 : 0
message = last_log.split("\n")[2..-2].join("\n")

unless updates.empty?
`growlnotify -s -t "#{project} Update - #{committer}"
-m "#{message + "\n\n" + updates.join("\n")}" -p #{priority} --image ~/bin/mph.png`
sleep 180
`~/bin/svngrowl.rb #{directory}`

All the bash script does is finds the proper directory for the project in question and passes it to the ruby script. The ruby script in turn does an svn up on the directory, collects all the interesting data, and runs growlnotify (the command line growl utility) displaying all of the interesting data. There is also a rescue statement in there that just restarts the process if something goes wrong (an error is thrown if svn can't update properly, which can happen if the network drops out or if you do svn st at the same time that this process is doing svn up). I also used the --image options to pass in a beautiful picture of Mr. Potato Head to use as the icon shown on the notification.

Please feel free to use any of these to make your work/play more productive (except for the picture of Mr. Potato Head... that one is mine!)