

My favourite Zsh features - joejag
http://code.joejag.com/2014/why-zsh.html

======
stormbrew
Something I've noticed is that osx users believe bash to be less capable than
it is because of the poor out of the box configuration of bash on that
platform (in addition to the ancient version installed). Particularly the tab
completion stuff. It doesn't pop up menus and all that, but the ubuntu install
of bash has a ton of context-sensitive tab completion stuff in it, and the git
package properly installs __git_ps1 and very good tab completion (which even
the homebrew git recipe on osx doesn't manage to do).

This is not to say that zsh doesn't have a lot more features, just that the
comparison from the perspective of an osx user tends to be a lot more stark.

~~~
0x0
I guess "bad PR" like this is actually one downside for projects switching to
GPL3.

~~~
jordigh
Well, bad PR from Apple. But you don't get much good PR from Apple with GPLv2
either, which they're slowly purging from their OS as well.

------
justinmayer
While we're on the topic of non-bash shells, I recommend taking a look at
Fish: [http://fishshell.com/](http://fishshell.com/)

I wrote a tutorial on how to install it on Mac OS X and Ubuntu:
[http://hackercodex.com/guide/install-fish-shell-mac-
ubuntu/](http://hackercodex.com/guide/install-fish-shell-mac-ubuntu/) For me,
the chief advantage to Fish is that you get more functionality out-of-the-box
than with most other shells, including zsh.

I also published two related projects for easily sharing Fish shell
enhancements — Tacklebox
[https://github.com/justinmayer/tacklebox](https://github.com/justinmayer/tacklebox)
and Tackle
[https://github.com/justinmayer/tackle](https://github.com/justinmayer/tackle))
— because I wanted a way for folks to be able to have access to multiple
plugin repositories and easily share their favorite shell snippets.

------
kstock
A killer feature not listed here is global aliases. These are aliases that can
be anywhere in a line. The most use I get out of this is from having

    
    
       alias -g L=' | less '
    

which allows me to simply append "L" to a line to pipe the output to less.

    
    
        ls L
    

The pattern of short all-caps global aliases for ' | command 's make
building/editing pipelines really easy/fast.

    
    
        alias -g C=' | wc -l '
        alias -g A=' | ack-grep '
        alias -g S=' | sort '
        alias -g JQL=' | jq -C  | less'
    
        ls **/*png L
        ls **/*png A -v regex C
        curl $site JQL
    

putting

bindkey '^g' _expand_alias

in your zshrc allows you to expand aliases with <C-g>

You can find more global aliases and tips at: [http://grml.org/zsh/zsh-
lovers.html](http://grml.org/zsh/zsh-lovers.html)

~~~
IgorPartola
So what do you do when you want to ls a file called "L"?

~~~
kstock
I put L in 'single quotes' or I \escape it

    
    
      touch 'L'
      ls 'L'
      ls \L

~~~
pmoriarty
Do _not_ use global aliases. They are dangerous. It's too easy to accidentally
use them without realizing it, with unpredictable consequences.

Much better is to use abbreviations which expand to the full command they
abbreviate after you hit the space bar.[1]

This way you can see exactly what's going to be done before you hit ENTER. It
does cost one extra keystroke, but the safety is worth it.

[1] -
[http://zshwiki.org/home/examples/zleiab](http://zshwiki.org/home/examples/zleiab)

------
jryan49
One of my favorites instead of aliasing ".."'s is this function:

    
    
      rationalise-dot() {
        if [[ $LBUFFER = *.. ]]; then
          LBUFFER+=/..
        else
          LBUFFER+=.
        fi
      }
      zle -N rationalise-dot
      bindkey . rationalise-dot
    

When you hit ... it will produce a slash and a ../ for each . you type after
that.

~~~
pmoriarty
Nice. But all you really need are:

    
    
      alias ..="cd .."
      alias ...="cd ../.."
    

After that, the more dots you type, the more error-prone it is, as you start
to have to carefully count exactly how many directories you have to go up to
get to where you want.

A better alternative is a script that shows a list of parent directories and
lets you select them by typing the number or letter associated with them.

For example, if your current directory is "/a/b/c/d/e/f/g/h", then the script
would display something like:

    
    
      List of parent directories:
      1 - a
      2 - b
      3 - c
      4 - d
      5 - e
      6 - f
      7 - g
      Please choose a directory: _
    

and you could type "3" to get to directory "c". That would be equivalent to
typing "......", but much less error-prone and it'll save you the tedium of
counting dots too.

~~~
JulianWasTaken
Error prone isn't really that important in a shell when we're just talking
about moving around. You type a bunch of dots which puts you in the region
more or less -- plus I never really go from 8 directories deep to 2, (I doubt
I even have an 8 directory deep section of my file tree) -- if I did I'd start
from /, so it's more about 4 or 5 or so, in which case it's easy enough not to
count but to know based on context. To each his own though.

------
andrewstuart2
The tab completion isn't limited to the beginning of file names either. Useful
when many of your file names start with the same pattern but then diverge.

    
    
      ls something<TAB>
    

will complete to

    
    
      ls prefixSomething.sh
    

if it's unique enough. This is probably my single favorite zsh feature.

~~~
taeric
Having gotten used to ido in emacs, I must say that I am now disappointed in
most all autocompletes. Shame it doesn't work in the shell. (Quick, someone
prove me wrong! Please! :) )

~~~
ash
How does ido work? Is there any demo or a quick tutorial? (I don't use Emacs.)

~~~
wging
[https://www.youtube.com/watch?v=AfZX39jd6cw#t=80s](https://www.youtube.com/watch?v=AfZX39jd6cw#t=80s)
Ignore the first 1:20 or so, in which he configures things the slow way.

The real magic of ido is the completion engine. It's not made super explicit
in that video, but it's actually possible to complete on arbitrary
subsequences of strings you want.

With my configuration (using the popular "flx-ido" matching engine), if you
wanted to match "README.md", you could achieve this by just typing ED. Even
though E and D aren't consecutive, E appears before D. (But
"GOOD_EDITING_SOFTWARE" would be matched before "README.md", because it
prioritizes consecutive matches and characters at the beginnings of logical
groups of characters.)

------
billiob
One feature not listed there that use a lot is "setopt autocd". Just type in a
directory name and hit Enter and it will automatically "cd" to it. No need to
alias ".." to "cd ..".

------
seniorsassycat
I love that if you have vi key bindings active you can update the prompt when
you change modes. I never used vi bindings in bash because I would become
confused when I entered normal mode without realizing it. In zsh it was easy
to configure my prompt to change colors and symbols when outside insert mode.

[https://github.com/everett1992/dotfiles/blob/master/home/.zs...](https://github.com/everett1992/dotfiles/blob/master/home/.zshrc#L91-L112)

I have noticed that zsh's globbing is greedy.

    
    
        `grep ^foo *` tries to expand ^foo when bash would pass it as a string to grep.

------
rafaelnonato
It seems to me that the only two features I can't get in my modern bash is
completion of the kind cd /firstletters/firstletters/<tab> ==>
/fullname/fullname and the keyboard navigable menus.

------
gcb0
bash only needs better history manipulation. absolutely nothing else.

all those z shell features the only useful one (i.e. the only one that's
impossible on bash) is the __recursion (i typed star star, but hn hides it)
hack.

and it's awful. because now you just learned something that you can't use
anywhere else! and to search that same way in a shell script? though luck.

also it has less parameter then find. and find is available everywhere so you
can use it in scripts.

~~~
barrkel
This works fine in bash:

    
    
        $ echo **/*.txt
    

Of course if you're using an ancient version of bash, you're out of luck.

    
    
        $ bash --version
        GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
        GNU bash, version 4.1.13(7)-release (x86_64-unknown-cygwin)

------
jradd
Any favorite command I reference is likely to be listed here:
[http://www.zzapper.co.uk/zshtips.html](http://www.zzapper.co.uk/zshtips.html)

------
changs
(Shameless self-promotion) I'd like to recommend a small and unobtrusive
config for ZSH:
[https://github.com/changs/slimzsh](https://github.com/changs/slimzsh) It is
almost a default ZSH, but with small tweaks here and there to make it even
nicer. I hope that you find it useful :)

------
arianvanp
Clever history doesn't really work for me when I use `sudo`

say I type

    
    
        $ sudo pacman -Syu 
        $ sudo chown blah blah
        $ sudo pa <UP>
    

I just get `sudo chown blah blah` instead of `sudo pacman -Syu`

Does anybody know how to fix this? :)

~~~
cornstalks
I don't see that behavior for me.

    
    
        $ sudo foo
        $ sudo bar
        $ sudo fo<UP>
    

gives me `sudo foo`.

I'm using zsh 5.0.7 (x86_64-apple-darwin14.0.0) on OS X 10.10 (with
prezto[1]).

[1]: [https://github.com/sorin-ionescu/prezto](https://github.com/sorin-
ionescu/prezto)

------
rnhmjoj
The up arrow to go back in history matching the partial command I typed is has
become essential to me.

I feel lost without it, more than the tab completion.

~~~
ealloc
You can do it in bash too. I have this in my bashrc:

    
    
        bind '"^[[1;5A": history-search-backward'
        bind '"^[[1;5B": history-search-forward'
    

where ^[ is the escape character. This way, crtl-up goes to previous partial
match (and up goes to last command as usual). I use it all the time.

~~~
jackalope
I have this to use the arrow keys without any modifier:

    
    
        # Use up/down arrows to search on partially typed command
        bind '"\e[A"':history-search-backward
        bind '"\e[B"':history-search-forward
    

Just type the first letter(s) and use the up/down arrows to scroll through the
filtered command history. Incredibly convenient.

------
krick
<CTRL>+X <CTRL>+E works in bash as well.

------
zobzu
interestingly you can s/bash/zsh/ and s/zsh/bash/ in this text and everything
also works.

~~~
luchs
How do you get a menu like in the second screenshot in bash?

~~~
Fastidious
There is no such menu (tried it on CentOS and OS X). It simply lists the
available directories.

~~~
zobzu
Note that he uses ohmyzsh. There's ohmybash too:
[https://github.com/revans/bash-it](https://github.com/revans/bash-it)

For menu complete with bash, the easiest is to add:

TAB menu-complete

inside of "~/.inputrc" then start a new shell to test it. Thats because it
uses readline to handle command line (and inputrc configures readline).

Note: im not saying the experience is not better in zsh, just that both can do
all this stuff. ive been switching between zsh and bash quite a few times
myself over the last decade and use bash daily most of the time lately.

In my eyes:

zsh:

\- nice and neat to configure/less bloat maybe

\- powerful scripting language

\- some scripting syntax requires zsh so when you get used to that... you
write non-portable stuff ;)

bash:

\- does approx everything zsh does and some more

\- scripting language works everywhere because everyone has default to bash

\- scripting language is slightly less powerful than zsh in some ways

\- configuration is a little more all over the place (just like the .inputrc
above)

Thus, all things considered, and given the improvements in bash over the last
past .. 5 years or so - i'm using bash more often even thus zsh is also a very
nice shell.

