Configuring The `help` Command In Zsh
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 typehelp
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 therun-help
command" from earlier) - set a new value for
$HELPDIR
(This environment variable tellsrun-help
where to look for its help files.) - create an alias for our new
run-help
command, calledhelp
, 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).