The switch to ZSH

2020-02-29

ZSH is an alternative to shells like sh, bash or fish. I have nothing against any of them but I choose to use ZSH. There are hundreds of articles that cover the benefits, but very few that I have found also cover the downsides. In this blog, I will discuss some of the reasons I use ZSH and some of the annoyances I face. I work as a penetration tester, so some of the annoyances are specific to that. I am not going to pretend that this is a comprehensive list, it is the things that made my decision.

To start with, I’ll talk about some of the features that make my life easier, the pros. It should come as no surprise that, as I use ZSH on a daily basis, the pros outway the cons for me; that is not to say however that I think zsh is perfect. It isn’t.

PRO: Bash Familiarity

ZSH is not strictly compatible with all BASH or SH features, (more on that later) but it is a lot more similar than some alternative shells. For me, this is important because I spend a lot of time SSHed into machines that have BASH or SH installed. It is often not possible for me to install ZSH so having a similar working environment is hugely beneficial.

PRO: Tab Completion

The tab completion on ZSH is hugely superior to that of bash. As well as giving descriptions of arguments, you can use the tab or arrow keys to cycle through each option

ZSH tab completion

Obviously, the tab completion is better with some tools than others, but zsh is able to fall back to the completion you would get in bash, with the bonus of being able to cycle through options.

PRO: Syntax Highlighting

We all use syntax highlighting in our code editors, why not also have it in our shell? You can see from the screenshot below that as soon as a valid command is input, you get feedback by it turning green. If an invalid command is input, it is red. It saves a lot of the embarrassing typos where you type gti instead of git, or sl instead of ls.

ZSH syntax highlighting

It should be noted that this isn’t a native ZSH feature, but a plugin.

PRO: Autosuggest

Another plugin is the autosuggestion plugin, it adds the last command from your history that matches what you have already typed. You can then use the right arrow key to accept the suggestion. This makes writing long but common commands much quicker.

ZSH autosuggestion

PRO and CON: ZLE

Zsh uses a tool called zle (zsh line editor) as an alternative to readline that most other shells use. Readline is also the tool used by the read command that many shell scripts use for getting user input.

ZLE is, subjectively, much more advanced than readline. Personally, my favourite feature is its superior vim emulation, meaning I can edit the command I am currently writing with the same keys I use to edit almost everything else I write (including this blog).

Hoverer, coming to my first annoyance, as it doesn’t use readline, your readline configuration isn’t read. This makes sense but readline is everywhere. Metasploit, pappy and bash all use readline as their line editor. You can configure them all in one place: .inputrc, that is all of them except zsh/zle.

That is not to say that you cannot configure zle to do the same things, you absolutely can, but it means making those configuration changes in multiple places.

CON: /dev/tcp (or lack thereof)

/dev/tcp/* is a non-standard feature that bash added. ZSH, does not implement this. There is a tool called ztcp which, like zle, is more powerful than the bash alternative but, in my opinion, not as easy.

That being said, I only really use that feature when I don’t have netcat available, that is when I am on a remote machine. When that is the case, I am normally in a bash environment anyway.

CON: stty raw -echo

When you get a netcat reverse shell, one of the first things you want to do is upgrade it to a fully interactive shell. When using Bash, you would do this by pressing Ctrl+z to background the current process, then typing stty raw -echo then typing fg and pushing enter twice.

If you try this in ZSH, it won’t work. Why? Because ZSH’s implementation resets the -echo option every time the prompt is drawn. If you’re interested in why, it is discussed here. But, what that means, is we need to foreground the shell, before the prompt is drawn. The solution:

stty raw -echo; fg <enter><enter>