Skip to main content

  • October 1, 2015

Gone zshin'

Terminal is one of the more powerful apps that comes pre-installed on the Mac. In a nut-shell (see what I did?), it’s an emulator for bash, which is a command processor that lets us interact directly with the UNIX-based operating system that makes the Mac go. As developers, designers and curious tinkerers alike, it’s safe to assume we all rely on it one way or another. Decorative Illustration

For some of us, that might mean firing up a build tool like Grunt or Gulp to speed up our front-end development. And for others, that might also mean tracking our changes in version control, managing remote servers, or some other sorcery that’s even beyond me.

Let’s take a look. Terminal.app can be found in your \Applications\Utilities\ folder. A simple spotlight search will also get you there pretty quick.

Out of the box, it’s pretty bare bones. Sure, we can adjust colors, fonts, install themes, etc., but the more we use it, the more we’ll want out of it. We are human, after all. Luckily, there are options. Let’s talk about how we can customize our command line experience and make it a little more enjoyable.

Hello, iTerm.

A few years back, I was introduced to iTerm, an alternative to Terminal that provides the same functionality with a whole bunch of amazing features like tabbed windows, split panes, mouseless copy, replay, and search. That’s just a few, but all things I can’t imagine living without.

Let’s look at a typical workflow scenario:

We have a pane that runs our Grunt task to compile CSS and JavaScript, a pane that runs a simple PHP development server so we can preview our work locally, and a pane to track our changes in a git repository. This would normally have taken 3 windows but now is contained in one that groups everything for that project together. For those that split time between projects, multiple tabs like this will come in handy. You may not realize it, but when hopping around a lot the time to ramp up/down adds up.

Don’t Bash bash

Bash is great. As a daily driver on your Mac it gets the job done. And if you’re managing remote servers in any flavor of Linux, you’re not going to want to replace bash there. But like most apps, it’s not our only option on the Mac. I’ve come to really enjoy Z-shell. Z-shell, or aptly named zsh (zish) is like bash’s younger sibling. It’s been around almost as long, incorporates many of bash’s core features, and comes packed with lots of extras.

To really highlight the power of zsh, we’re going to take a look at oh-my-zsh, an extremelly popular community-driven framework for managing your zsh profile.

Let’s Do This

The easiest way to get started with zsh and oh-my-zsh is to follow the README. Installation is pretty simple. We’re going to execute a single curl command and let oh-my-zsh do its thing.

sh -c "$(curl -fsSL 'https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh')"

Not too bad, right? With oh-my-zsh installed and zsh configured as our default shell, we can start to look at some of the awesome things we can do.

Tab Completion

Navigating the filesystem is pretty simple with Finder. But sometimes it’s tricky to remember exactly where you’re going. With tab completion, we no longer need to dig through deeply nested folders, and instead enter a cd and <tab> to see suggestions on where you can go.

Try it: cd ~/ <tab>

Shorthand

This one is pretty similar to tab completion, but it takes it a step further and narrows down the suggestions based on what you’ve started to type.

Try it: ls ~/Desk <tab>

Hinted History

When learning how to use the command line, arrow-up is one of the first tricks you’ll become familiar with. It’s a simple way to re-trace your steps and repeat commands. This is great for restarting tasks or repeating commands you execute often. But what if we’re all over the place and the command we’re looking for is deep in our history? Problem solved. With hinted history, you can filter by beginning with the starting command and then arrowing up.

Try it: git <up>

Shared History

Speaking of history… Let’s say we add a new pane, but we don’t want to start all over again with a brand new shell. In Terminal, we’d have access to your history from the last time we closed the app. Now, we can just pick right up where we left off and arrow-up will act as if we never even left.

Help?

I like to save the best for last, so this is one of my favorites. Most commands accept options which allow us to be more specific about what we’re trying to do. Naturally, options vary between commands, but there are a couple of staples like -h for help and -v to determine which version we’re running. To really dive deep, reference the manpages with a quick man git. But man (heh..), there’s an awful lot to digest.

To get a quick refresher on options, type the command with a dash and a tab then tab again to select an option and continue on.

Try it: rm -<tab>

Config

During installation, ohmyzsh created a new profile for us at ~/.zshrc. Let’s open that up in our favorite text editor and see what’s going on.

One of the first things I like to do is update the example aliases that give me quick access to this config file and my working copy of oh-my-zsh. Scroll down to the very bottom of this file and look for #Example aliases.

Since I use Sublime Text with the command line launch alias subl, I update the 2 samples and change them to open right into my editor for quick access. If you’re using TextMate or Atom, adjust accordingly, save and close.

# Example aliases
alias zshconfig="subl ~/.zshrc"
alias ohmyzsh="subl ~/.oh-my-zsh”

Note: Any time you make changes to your zsh config file, you’ll need to source it by typing zsh.

Now, a simple zshconfig pops us right back into our config file. If you’re no stranger to setting up an alias, this may seem simple. But it really only scratches the surface, so hang with me.

Themes

Don’t close that config file just yet. Let’s talk about themes. At the top of our config file we’ll see an environment variable for ZSH_THEME=“robbyrussell”. Simply put, changing this will update the theme and change the way our iTerm window looks.

If you’ve got some time on your hands, you can browse what’s available and pick one that you can really identify with. And if you’re feeling adventurous, try creating your own. Call me old fashioned, but I personally dig the robbyrussell theme.

Plugins

Here’s where it starts to get good; where oh-my-zsh really earns its place at the table. In my opinion, a framework is only as powerful as the community behind it. And the oh-my-zsh plugin ecosystem is pretty strong.

Unlike most frameworks where installation is required to use a plugin, oh-my-zsh ships with them at the ready. We just need to enable them. But before we jump in and turn on all the things, let’s take a look at the Wiki and see what’s available. And if you recall, we configured 2 example aliases in our config file – zshconfig, which loads our config file into our chosen text editor, and ohmyzsh, which is a quick and easy shortcut to load the entire framework as a project into our editor.

With our project view open, we see a list of folders, but we’re going to focus on the plugins directory. By expanding this folder, we can browse through and familiarize ourselves with each of the plugins by name, and even dive into the source files to see exactly how they work. Depending on what kind of development we’re doing, or what we use the command line for, there’s a little something in here for everybody.

Installing a plugin is as easy as adding it to our main configuration file. On the command line, type zshconfig to load up the config in our editor and locate the plugins variable.

# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=()

As a test, let’s install the git plugin:

plugins=(git)

Now we can save and close our config file, reload our zsh profile with a quick zsh on the command line, and start taking advantage of a wealth of really helpful shortcuts for everyday commands like:

g: git
ga: git add
gst: git status
gl: git pull
gp: git push

At a very high level, this allows us to do more by typing less. Are you sold yet? It might seem silly to rely on a plugin to alias simple commands we can easily remember. But before we know it we’ll be doing some serious cleanup with shortcuts like gbda and viewing logs with glola magic. Take a look and try committing those to memory. You’ll feel like a rockstar every time. I promise.

Make it Yours

Creating plugin for ohmyzsh really couldn’t be easier. With a simple example.zsh file located in our custom/ folder, we’ve got all we need to hit the ground running. So, let’s open that file and save it as awesome.sh and write a simple function that learns our name and says hello.

awesome.sh

# say hello
function hello() {
 echo -e "What's your name? \c "
 read name
 echo "Hi $name!"
}

With our plugin complete, all we have left to do is install it by adding it to the list of plugins in our config file as such:

plugins=(git awesome)

Remember we need to reload our profile with a zsh whenever we make changes. With our new plugin loaded, we can type hello and bask in the glory of our first machine learning robot. #maker

Is this actually useful? Nah. I know. But hopefully the light is going off for you. But just in case it hasn’t yet, let’s try something a little more useful.

I love Craft. Hopefully you do too. Aside from client work, I set it up a lot just to test stuff out and experiment. Sure, I could download and extract the zip, do all the permissions stuff, setup a virtualhost, a database, and boom goes the dynamite. That’s all super easy. But I want to do it faster. And I don’t want to have to think about it too much.

Let’s add a new command line tool to our awesome plugin that does it for us.

awesome.sh

function new_craft() {
 echo -e "What should we call this project? \c "
 read PROJECT_NAME
 mkdir $PROJECT_NAME && cd $PROJECT_NAME

 mkdir -p tmp
 curl "http://buildwithcraft.com/latest.zip?accept_license=yes" -L -o tmp/craft.zip
 unzip tmp/craft.zip
 pushd craft
 chmod 774 app config storage
 popd
 mv public/htaccess public/.htaccess
 rm public/web.config
 rm -rf tmp

 echo "<?php
 if (file_exists(__DIR__ . '/' . \$_SERVER['REQUEST_URI'])) {
 return false;
 } else {
 include_once 'index.php';
 }" > public/router.php

 mysql -uroot --password= -e "create database if not exists craft_local_$PROJECT_NAME";

 echo "<?php
 return array(
 'server' => 'localhost',
 'user' => 'root',
 'password' => '',
 'database' => 'craft_local_$PROJECT_NAME',
 'tablePrefix' => 'craft'
 );" > craft/config/db.php

 pushd public
 php -S localhost:4000 router.php
}

Now we can reload our profile with zsh and type new_craft to give our robot a little more of a purpose. When all is done, we’ll be running a fresh installation of Craft on localhost:4000. And all we have to do is go to /admin/install to wrap.

TMI?

If you made it this far, thanks for hanging in there. I could keep going but we’ve all got work to do. Hopefully some of the stuff we covered makes your life a little easier and your work more enjoyable. Until next time…

Back to Top