Cover of the Beatles' 'Help' album.
Photo attribution here.

The purpose of this post is to set up the help command for folks who are using the Zsh shell (like I am). If you're using Bash or another shell, feel free to skip this one.

Up until 2019, the default shell for Mac was Bash. When Apple released macOS Catalina, Apple started shipping Zsh as the default shell instead. This was possibly done because Bash changed its software license from GPL2 to GPL3. The difference between the two is that GPL3 requires that "code built with GPL3-licensed packages must open-source that code". This is likely not something that was compatible with Apple's business model.

As a result, we as Mac-using shell students now have to spend a few mental cycles on the subtle but sometimes important differences between Bash and Zsh. One of those differences is with the help command, which is usable out-of-the-box in Bash but which has a few hurdles in Zsh.

The problem with help in Zsh

By default, when we type help set in the default Zsh terminal, we see the following:

$ help set
zsh: command not found: help
$ 

However, if we open up Bash and type the same command, we see the following:

$ bash

  The default interactive shell is now zsh.
  To update your account to use zsh, please run `chsh -s /bin/zsh`.
  For more details, please visit https://support.apple.com/kb/HT208050.
  bash-3.2$ 
  bash-3.2$ 
  bash-3.2$ help set
  set: set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
          -a  Mark variables which are modified or created for export.
          -b  Notify of job termination immediately.
          -e  Exit immediately if a command exits with a non-zero status.
          -f  Disable file name generation (globbing).
          -h  Remember the location of commands as they are looked up.
          -k  All assignment arguments are placed in the environment for a
              command, not just those that precede the command name.
          -m  Job control is enabled.
          -n  Read commands but do not execute them.
          -o option-name
              Set the variable corresponding to option-name:
                  allexport    same as -a
                  braceexpand  same as -B
                  emacs        use an emacs-style line editing interface
                  errexit      same as -e
                  errtrace     same as -E
                  functrace    same as -T
                  hashall      same as -h
  ...

As it turns out, there is a run-help command in ZSH, but it isn't turned on by default. Instead, for some reason it's simply aliased to the man command:

$ which run-help
run-help: aliased to man
$ 

If you were to type run-help set, for example, you'd see the same "BUILTIN" page that we saw when running man set. Not too helpful, since help is supposed to be our recourse when man doesn't have the info we need.

However, a real, non-aliased run-help command does exist. We just have to activate it ourselves. But should we in fact do that?

Unlocking the help command in Zsh

To continue making progress and run help set successfully, we have 3 options:

  • Change our default shell from Zsh to Bash, so that every time we open a new terminal tab, we see a Bash prompt. This is a completely valid option- Bash is one of the most popular shells in-use today.
  • Activate the run-help command on our machine, and then create an alias which executes that command every time we type help in our terminal. This is the option that I chose for my machine, since I've already customized my Zsh prompt and I don't want to have to do so again with a Bash prompt.
  • Make no permanent changes, and instead simply remember to log into Bash each time we want to run help. If you're a novice and want to minimize any config changes to your machine, then this is the way to go. But it's also the option which results in the most legwork in the long run.

I'll briefly go over the first two options below. Hopefully the third option doesn't require any explanation- you literally just run the bash command in your Zsh terminal, and then run help at your newly-opened Bash prompt.

Option 1: Changing the default shell to Bash

The first option we have is to simply switch our default shell to Bash. We can do this by entering the following command in our shell:

chsh -s /bin/bash

According to its man entry, the chsh, chpass, and chfn commands all do the same thing:

NAME
chpass, chfn, chsh – add or change user database information

...

-s newshell    Attempt to change the user's shell to newshell.

So this command "add(s) or change(s) user database information". At the bottom of the output, we see that the -s flag "(a)ttempt(s) to change the user's shell to newshell." Pretty straightforward.

When we run this command in our terminal tab and then open a new shell, we should see a Bash prompt. On my machine, I see:

Last login: Fri Jan 12 12:02:51 on ttys012

The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
richies-mbp:part-0 richiethomas$ 

This is the Bash prompt as it appears on my machine.

And if we want to change our default shell back to Zsh, we simply run the command again, with /bin/zsh (or the location of Zsh on your machine) as a parameter instead of /bin/bash. To find the correct location to use as a param, run which zsh.

Option 2: Aliasing run-help to help

As mentioned before, we could just remember to log into Bash whenever we need to run help. But speaking for myself, I don't want to have to do this every single time I open a terminal tab (which is every day). I'm lazy, and I'd rather make a one-and-done configuration change, and continue to use ZSH as I have done so far.

After some Googling around, I found this StackOverflow question, with this answer describing how to make the help output more helpful (pun intended):

...put this into ~/.zshrc:

unalias run-help
autoload run-help
HELPDIR=/usr/share/zsh/"${ZSH_VERSION}"/help
alias help=run-help

If you're on macOS and installed using Homebrew, then you will want to replace the HELPDIR line with this:

HELPDIR=$(command brew --prefix)/share/zsh/help

It's telling me to:

  • unalias the current definition of the run-help command (which is aliased to "man" by default in Zsh)
  • autoload a new implementation of the run-help command (this is what I meant by "manually turn on the run-help command" from earlier)
  • set a new value for $HELPDIR (This environment variable tells run-help where to look for its help files.)
  • create an alias for our new run-help command, called help, which is just shorter and easier to type.

This all sounds fine, except the very last step related to $HELPDIR. I tried...

HELPDIR=$(command brew --prefix)/share/zsh/help

...instead of...

HELPDIR=/usr/share/zsh/"${ZSH_VERSION}"/help

...but this resulted in me seeing unexpected output when typing help set (specifically, the man entry for something called zshbuiltins, which is not what I wanted).

So I kept the original value of $HELPDIR mentioned in the first block of code, and that resulted in me seeing this:

$ help set
  set [ {+|-}options | {+|-}o [ option_name ] ] ... [ {+|-}A [ name ] ]
      [ arg ... ]
         Set  the options for the shell and/or set the positional parame-
         ters, or declare and set an array.  If the -s option  is  given,
         it  causes the specified arguments to be sorted before assigning
         them to the positional parameters (or to the array name if -A is
         used).   With  +s  sort  arguments in descending order.  For the
         meaning of the other flags, see  zshoptions(1).   Flags  may  be
         specified by name using the -o option. If no option name is sup-
         plied with -o, the current option states are printed:   see  the
         description  of setopt below for more information on the format.
         With +o they are printed in a form that can be used as input  to
         the shell.
  
         If  the -A flag is specified, name is set to an array containing
         the given args; if no name is specified, all arrays are  printed
         together with their values.
  ...

This is the output we want.

Note that I had to either open a new terminal tab or run source ~/.zshrc in order for this change to take effect.

Wrapping Up

With this change complete, we'll now be able to run help in our Zsh terminal, and get equivalent output to what we'd see in a Bash terminal.

Photo Attribution

Title: Unknown

Description: n/a

Author: No author specified.

Source: The Center For Respect

License: CC BY-NC-ND 3.0 DEED Attribution-NonCommercial-NoDerivs 3.0 Unported

License information comes from Google Images (screenshot here).