Mind Like Water

Automate the command line with a custom bash script

I spend a lot of time on the command line these days. Often I find myself typing very similar commands over and over again. For example, any time I want to launch a Rails console on Heroku, I have to type a command like this:

heroku run rails console -a my-app-staging

(The app name is optional if you only have one Heroku app associated with the current git repository. However, I often have multiple environments, say, staging and production, which means I'm often manually typing app names.)

Today I will show you how to automate this and other commands like it by setting up a custom bash script, so you can type a simple command and the rest is handled automatically, e.g.

[custom-bash-script-name] console

Our simple script has several requirements:

  1. We should be able to specify the environment in which to run the command, but default to staging if no environment is specified.

  2. For each environment, the script should be able to derive the Heroku app name.

  3. For each command, the script should output the actual executed command.

To start, pick a name that is relatively uncommon, but easy to type. For my script, I chose beorn, which is a character from The Hobbit.

In order to to specify the environment we write a simple case statement that will check the first argument to our command. If it matches a known environment, we'll use that, otherwise we set a default:

case "$1" in
  production) environment=production; shift;;
  staging) environment=staging; shift;;
  * environment = staging;;
esac

This will allow us to type beorn console, which is a shortcut for beorn staging console, or beorn production console when our environment differs from the default.

To derive our Heroku app name, we write another case statement based on the environment:

case "$environment" in
  staging) app=my-app-staging;;
  production) app=my-app-production;;
esac

Now, we want to add the first command to our script. We could call it console, but there are many other Heroku commands starting with heroku run so instead we'll start with the more generic run.

To satisfy our third requirement, we write a simple function that outputs the full command and then executes it.

echo_exec() {
  echo " -> $@"
  $@
}

run() {
  echo_exec "heroku run $@ --app $app"
}

case "$1" in
  run) $@;;
  console) run rails console;;
  *)
    echo "Error."
    exit 1
    ;;
esac

Here we define a function run that outputs the generated command and then executes it, and then set up a case statement to determine when to run the command. We could type beorn run rails console and get away without defining a console command, but the shorter beorn console is about as terse as it gets:

beorn console
 -> heroku run rails console --app my-app-staging
beorn production console
 -> heroku run rails console --app my-app-production

Because we opted for the more generic run command, more obscure Heroku commands we weren't anticipating will still work, e.g.

beorn run rake -T
 -> heroku run rake -T --app my-app-staging
beorn production run rake -T
 -> heroku run rake -T --app my-app-production

There you have it! If you'd like to view the entire script at once, I've created a gist. There are many more cool things you can do with custom bash scripts, but this should give you a small taste of the possibilities.