In zsh, what is the `setopt` builtin for, how does it relate to `unsetopt`, and how would you find out which shell options are currently enabled?
answer
- boolean switches, not variables
- setopt / unsetopt
- the NO_ prefix flips it
- no arguments lists them
- names ignore case and underscores
basics
~20 ssetopt turns a named zsh behaviour on and unsetopt turns it off; setopt NO_NAME means the same as unsetopt NAME. Typed with no arguments, setopt lists the options currently on and unsetopt lists those currently off.
solid answer
~50 szsh's behaviour is controlled by a large set of named boolean switches called options — things like `AUTO_CD` (typing a directory name changes into it), `AUTO_PUSHD`, `CORRECT`, `SHARE_HISTORY`. You enable one with `setopt AUTO_CD` and disable it with `unsetopt AUTO_CD`; `setopt NO_AUTO_CD` is an exact synonym for the latter, which is handy when you want a single mechanism. Option names are matched case-insensitively and ignore underscores, so `AUTO_CD`, `auto_cd` and `autocd` are the same option — that is why you see all three spellings in real configurations. Typed with no arguments, `setopt` prints the options currently on and `unsetopt` prints those currently off. In a script or function, `[[ -o autocd ]]` tests the state rather than assuming it. Options set at the prompt last only for that shell; put them in `~/.zshrc` to make them stick for interactive shells.
code
bash · 7 linessetopt AUTO_CD AUTO_PUSHD # turn two options on
unsetopt BEEP # same as: setopt NO_BEEP
setopt # print the options currently on
unsetopt # print the options currently off
[[ -o autocd ]] && echo "AUTO_CD is enabled"go deeper
Recall that setopt turns a named zsh behaviour on, unsetopt turns it off, and that the lines go in ~/.zshrc to survive a new terminal.
Explain that names ignore case and underscores, that NO_X is the same as unsetting X, and how to list what is currently on or off.
Show judgment about which options you impose on a shared or production host, and use [[ -o name ]] rather than assuming any default.
Decide how much default behaviour a team standard is allowed to change: every non-default option is something a colleague must learn before your shell makes sense to them.
## Options are not variables A zsh option is a named boolean switch built into the shell, not a parameter you assign. `AUTO_CD=1` does nothing useful — it creates an ordinary variable that the shell ignores. The only way to change an option is through the `setopt` / `unsetopt` builtins (or the `set -o` / `set +o` interface inherited from the Bourne family). That distinction matters because options change *parsing and behaviour*, not data. They alter how the shell reads a line, what a bare word means, what happens on an error — which is why they are a shell feature rather than an environment variable. ## Turning them on and off ```zsh setopt AUTO_CD # on unsetopt AUTO_CD # off setopt NO_AUTO_CD # also off - the NO_ prefix inverts ``` The `NO_` prefix exists so a configuration can express every change with one builtin, which reads more consistently in a long list. Some options are on by default — `BEEP` is the classic — so making the shell quiet is `unsetopt BEEP` (or `setopt NO_BEEP`), not a `setopt` of something. ## Names are forgiving Option names are compared ignoring case and underscores. All of these are the same option: ```zsh setopt SHARE_HISTORY setopt share_history setopt sharehistory ``` This is why documentation, blog posts and framework code all look slightly different from each other. Pick one style — the screaming-snake form is the most readable in a config file — and stay consistent. ## Inspecting the current state Two quick views: - `setopt` with no arguments prints the options that are currently **on**. - `unsetopt` with no arguments prints the options that are currently **off**. Both are long lists, so pipe them through a filter. For a programmatic check, use the option test in a conditional: ```zsh if [[ -o autocd ]]; then echo "AUTO_CD is enabled" fi ``` That form is the correct one to use inside a function that needs to behave differently depending on how the user has configured their shell — never assume a default. ## Where to put them An option set at the prompt applies to that shell only and vanishes when it exits. To make it permanent for interactive shells, put it in `~/.zshrc`. That is deliberate: nearly every option worth setting changes interactive behaviour, and shells that run scripts have no business inheriting your line-editing preferences. Inside a function, options leak into the calling shell unless you scope them. `setopt LOCAL_OPTIONS` at the top of a function makes option changes revert when the function returns, and `emulate -L zsh` does the same while also resetting options to zsh defaults for the body — useful when you are writing a function that others will source into a shell configured differently from yours. ## Options worth knowing A short, representative sample rather than a catalogue: - `AUTO_CD` — a bare directory name acts as `cd`. - `AUTO_PUSHD` — every `cd` pushes onto the directory stack, so you can walk back. - `CORRECT` — offers spelling corrections for command names (`CORRECT_ALL` extends it to arguments, which many people find too aggressive). - `INTERACTIVE_COMMENTS` — allows `#` comments on an interactive command line. - `BEEP` — on by default; the first thing many people turn off. ## The judgment part Options are the cheapest way to make a shell feel like yours and the cheapest way to make it unusable for anyone else. Every non-default option is something a colleague pairing with you has to discover. `CORRECT` in particular changes what happens when you make a typo, which can be startling on a production host. Keep the list short and deliberate, and keep it in version control so you can explain — to yourself, six months later — why each line is there.
- Why does `AUTO_CD=1` not enable that behaviour?Because options are not parameters. That assignment just creates an ordinary shell variable called `AUTO_CD` that nothing reads. Options live in the shell's own state and are changed only through `setopt`/`unsetopt` (or `set -o`/`set +o`). It is a common first mistake when porting a configuration.
- You write a function that needs a particular option, but you do not want to change the user's shell. What do you do?Scope the change. `setopt LOCAL_OPTIONS` at the top of the function makes any option changes revert on return; `emulate -L zsh` does the same and additionally resets options to zsh defaults for the body. Both are the polite way to write a function that other people will source.
- Where should `setopt` lines live so they take effect for every terminal you open?`~/.zshrc` — it is read by interactive shells, which is the only place these options matter. Putting them in the always-read environment file would impose line-editing behaviour on scripts and remote commands that have no terminal at all.
saying these in an interview costs you the question
- Treats options as environment variables to export
- Thinks setopt NO_X is a different option from X
- Assumes option names are case-sensitive
- Sets options at the prompt and expects them to persist
- Cannot say how to list which options are on