Zsh has seen wide adoption by developers looking to improve their interactive shell experience. I’m rather late to this party, but I’d like you to join too.
I started cultivating a bash profile ever since I first logged into a shell. I’ve collected tab completions, aliases and functions that help get repetitive tasks done quick. When Zsh started to become popular the blogs and comments all focused on features I already had configured in my bash profile. I remained unconvinced.
Then I read about oh-my-zsh. A project that assembles good defaults for Zsh which has significant traction online. Being a late adopter, I’m writing this in a way that would of convinced me to switch shells immediately.
If you are confident with Bash and concerned about losing the knowledge you’ve built up. Then please don’t worry, 99% of what you do in Bash works the same way in Zsh. You can change shells without losing the knowledge you’ve built up.
This guide uses Zsh version 5.0.2 and oh-my-zsh updated to the date of this article. I have not changed anything from the base install.
When you see <TAB> in the examples it means hit the tab key, please don’t type it in as is.
Tab completion on ‘cd’
Let’s start off with a task we use all the time. The humble change directory command.
In Bash when you press <TAB> you get prompted with a list of files in the current directory.
In the context of the cd command this isn’t particularly useful, as you can only go into directories. Zsh knows this and only shows you the possible valid destinations.
Not only does it help you with matches, it also allows you to use your keyboard to navigate to the directory you want.
The combination of an intelligent TAB complete and using the keyboard to interact with options is at the heart of what makes Zsh a joy to use.
You don’t have to type whole directory names, just type the first few letters enough to make it unique and Zsh will work the rest out.
You may be familiar with using <CTRL>+R for performing a recursive search to find a previous command you typed in. This is a great way to reuse commands in Bash and Zsh.
Zsh goes one better. You can type part of a command and press <UP>
It finds the last command we typed starting with ‘ls’. We could continue pressing up to cycle if we wanted.
Shared command history
In Bash each shell has it’s own history. Zshs shares the command history with all active shells. This means you don’t have to remember where you typed that command.
Expand environment variables
We have environment variables available in our shells. Sometimes we want to manipulate the value of these variables or just visually inspect them
In Zsh you can press <TAB> to expand the value out.
Killer tab completion
I usually kill commands after inspecting them using ps or if I’m confident with pkill, Zsh give you another option.
Hit tab and it will give you a keyboard navigable list of commands that start with the letters you typed after kill
What was that switch?
To figure out how a command works you often try executing it either without parameters, with –help or look at the man page. Zsh gives you another option.
Type the start of the switch then press <TAB>.
This lists the switch name with inline documentation. You have the option to use keyboard navigation too.
This isn’t constrained to just the ls command. It works on a bafflingly large amount of commands like netstat, git and chmod.
Help with Git
Everyone has their favourite aliases for git commands. oh-my-zsh has a bunch out of the box too.
It also improves your prompt when you enter a git controlled directory.
You can see the branch name I’m on and that little lightning bolt is telling me I have uncommitted changes in my working tree.
Your last command failed
You may have noticed the green arrow at the start of my prompt in the screenshots. This indicates that my last command completed successfully.
If my command fails the prompt turns red until another command is successful.
In Bash I’m often using the find command along with xargs to find things and perform tasks with them. Zsh covers the majority of these scenarios with built in globbing support.
Let’s say we have this project checked out and we wanted to just find files that changed today.
We can add a modifier to the ls search pattern to filter for just what we want
Another handy trick is to use ** which performs a recursive search. Where can I find an example of a Rakefile under this directory?
Let’s use a modifier again to recursively find files over 20mb.
We aren’t limited to just using ls. How many lines of Clojure code do I have in this project?
Let’s say we want to recursively delete most of the Clojure files in this project
Hmm. I’d rather tbe sure about this. So let’s press tab to get all the files listed explicitly instead.
Did you mean this instead?
Every now and again we forget the case of file names, or type the middle part of a name rather than the beginning by mistake. Zsh knows we do this, and auto-corrects us.
As well as git aliases, oh-my-zsh has a bunch of useful everyday aliases.
I’m a big fan of using … to help you move up two directories.
Tabs named after the running process
Having the tab name changed to be the same as the running process is useful when you are hunting down where you are running that server.
Edit that long command in Vim
You can manipulate long commands in Bash and Zsh by using shortcuts like <CTRL>+K to delete characters. But, yet sometimes you want the power of a more powerful editor for manipulating commands.
Whenever you find yourself in this position hit <CTRL>+X <CTRL>+E to drop the current command into your $EDITOR.
We can edit the command and save quit to get it back on our terminal.
Plugins for your favourite tool
oh-my-zsh has a comprehensive list of plugins for tools you may use. I use the rake plugin which allows you to tab into available rake commands from your Rakefile.
Double <TAB> to enter a keyboard navigable list.
I wasn’t aware of how useful Zsh is an interactive shell until recently. The big reasons to change shell are:
- Tab complete and navigate all the things
- A vibrant plugin community providing a sensible baseline for our dotfiles
- 99% of what you know from Bash still works
Are you ready to chsh?