ZSHPARAM(1)

๐ŸŒธ hi bestie, welcome to zshparam ๐ŸŒธ

okay so this page is from the General Commands Manual and it's literally all about zsh parameters โ€” like, the whole lore. it is long so we're doing this in parts, and this is part one. buckle up ๐ŸŽ€


โœจ NAME โœจ

zshparam โ€” zsh parameters. that's it, that's the name, slay.


๐Ÿ’– DESCRIPTION ๐Ÿ’–

okay so a parameter has three things going on: a name, a value, and a number of attributes. and the name? it can be any sequence of alphanumeric characters and underscores, OR it can be one of these single-character icons: *, @, #, ?, -, $, or !. (yes literally just one character. main character energy.)

a parameter whose name begins with an alphanumeric or underscore is also referred to as a variable. iykyk.

the attributes of a parameter decide the type of its value โ€” people call that the parameter type or variable type โ€” and they also control other processing that may get applied to the value when it's referenced. the value type can be:

  • a scalar (a string, an integer, or a floating point number)
  • an array (indexed numerically)
  • an associative array (an unordered set of name-value pairs, indexed by name, also referred to as a hash)

named scalar parameters can have the exported, -x, attribute, which copies them into the process environment, and that environment then gets passed from the shell to any new processes it starts. exported parameters are called environment variables. the shell also imports environment variables at startup time and automatically marks the corresponding parameters as exported. ngl, some environment variables are not imported โ€” for reasons of security, or because they would interfere with the correct operation of other shell features. not everything gets an invite to the party ๐Ÿ’…

parameters may also be special, meaning they have a predetermined meaning to the shell. special parameters cannot have their type changed or their readonly attribute turned off, and if a special parameter is unset and then later recreated, the special properties will be retained. iconic, honestly.

to declare the type of a parameter, or to assign a string or numeric value to a scalar parameter, use the typeset builtin. ๐Ÿซถ

the value of a scalar parameter may also be assigned by writing:

name=value

in scalar assignment, value is expanded as a single string, in which the elements of arrays are joined together. filename expansion is not performed unless the option GLOB_ASSIGN is set. noted. โœ๏ธ

when the integer attribute, -i, or a floating point attribute, -E or -F, is set for name, the value is subject to arithmetic evaluation. and get this โ€” by replacing = with +=, a parameter can be incremented or appended to. See the section Array Parameters and Arithmetic Evaluation (in zshmisc(1)) for additional forms of assignment.

not me warning you: assignment may implicitly change the attributes of a parameter. for example, assigning a number to a variable in arithmetic evaluation may change its type to integer or float, and with GLOB_ASSIGN assigning a pattern to a variable may change its type to an array. sneaky but valid ๐Ÿ’€

to reference the value of a parameter, write $name or ${name}. See Parameter Expansion in zshexpn(1) for complete details โ€” that section also explains the effect of the difference between scalar and array assignment on parameter expansion. go read it, bestie, it's giving essential.


๐Ÿฆ‹ ARRAY PARAMETERS ๐Ÿฆ‹

to assign an array value, write one of:

set -A name value ...
name=(value ...)
name=([key]=value ...)

if no parameter name exists, an ordinary array parameter is created. if the parameter name exists and is a scalar, it is replaced by a new array. out with the old, in with the new ๐Ÿ’…

in the third form, key is an expression that will be evaluated in arithmetic context (in its simplest form, an integer) that gives the index of the element to be assigned with value. in this form, any elements not explicitly mentioned that come before the largest index to which a value is assigned are assigned an empty string. the indices may be in any order. and note that this syntax is strict: [ and ]= must not be quoted, and key may not consist of the unquoted string ]=, but is otherwise treated as a simple string. the enhanced forms of subscript expression that may be used when directly subscripting a variable name, described in the section Array Subscripts below, are not available here. rules are rules ๐ŸŽ€

the syntaxes with and without the explicit key may be mixed. an implicit key is deduced by incrementing the index from the previously assigned element. note that it is not treated as an error if latter assignments in this form overwrite earlier assignments. no drama.

for example, assuming the option KSH_ARRAYS is not set, the following:

array=(one [3]=three four)

causes the array variable array to contain four elements one, an empty string, three and four, in that order. cute, right? โœจ

in the forms where only value is specified, full command line expansion is performed.

in the [key]=value form, both key and value undergo all forms of expansion allowed for single word shell expansions (this does not include filename generation) โ€” these are as performed by the parameter expansion flag (e) as described in zshexpn(1). nested parentheses may surround value and are included as part of the value, which is joined into a plain string; this differs from ksh which allows the values themselves to be arrays. a future version of zsh may support that. (manifesting ๐Ÿ™) to cause the brackets to be interpreted as a character class for filename generation, and therefore to treat the resulting list of files as a set of values, quote the equal sign using any form of quoting. example:

name=([a-z]'='*)

to append to an array without changing the existing values, use one of the following:

name+=(value ...)
name+=([key]=value ...)

in the second form key may specify an existing index as well as an index off the end of the old array; any existing value is overwritten by value. also, it is possible to use [key]+=value to append to the existing value at that index. so many flavours, all valid ๐Ÿ’œ

within the parentheses on the right hand side of either form of the assignment, newlines and semicolons are treated the same as white space, separating individual values. any consecutive sequence of such characters has the same effect. basically they're all just vibes separators.

ordinary array parameters may also be explicitly declared with:

typeset -a name

associative arrays must be declared before assignment, by using:

typeset -A name

when name refers to an associative array, the list in an assignment is interpreted as alternating keys and values:

set -A name key value ...
name=(key value ...)
name=([key]=value ...)
heads up bestie: only one of the two syntaxes above may be used in any given assignment โ€” the forms may not be mixed. this is unlike the case of numerically indexed arrays. pick a lane ๐Ÿ’€

every key must have a value in this case. note that this assigns to the entire array, deleting any elements that do not appear in the list. the append syntax may also be used with an associative array:

name+=(key value ...)
name+=([key]=value ...)

this adds a new key/value pair if the key is not already present, and replaces the value for the existing key if it is. in the second form it is also possible to use [key]+=value to append to the existing value at that key. expansion is performed identically to the corresponding forms for normal arrays, as described above. consistency slay ๐Ÿ’…

to create an empty array (including associative arrays), use one of:

set -A name
name=()

๐Ÿงš Array Subscripts ๐Ÿงš

individual elements of an array may be selected using a subscript. a subscript of the form [exp] selects the single element exp, where exp is an arithmetic expression which will be subject to arithmetic expansion as if it were surrounded by $((...)). the elements are numbered beginning with 1, unless the KSH_ARRAYS option is set, in which case they are numbered from zero. know the difference, it matters ๐ŸŒˆ

subscripts may be used inside braces used to delimit a parameter name, thus ${foo[2]} is equivalent to $foo[2]. if the KSH_ARRAYS option is set, the braced form is the only one that works, as bracketed expressions otherwise are not treated as subscripts. ok queen, use the braces.

if the KSH_ARRAYS option is not set, then by default accesses to an array element with a subscript that evaluates to zero return an empty string, while an attempt to write such an element is treated as an error. for backward compatibility the KSH_ZERO_SUBSCRIPT option can be set to cause subscript values 0 and 1 to be equivalent; see the description of the option in zshoptions(1). legacy behaviour, we respect it ๐Ÿซก

the same subscripting syntax is used for associative arrays, except that no arithmetic expansion is applied to exp. however, the parsing rules for arithmetic expressions still apply, which affects the way that certain special characters must be protected from interpretation. see Subscript Parsing below for details. yes, there's a whole other section. we'll get there.

a subscript of the form [*] or [@] evaluates to all elements of an array; there is no difference between the two except when they appear within double quotes. check it:

  • "$foo[*]" evaluates to "$foo[1] $foo[2] ..."
  • "$foo[@]" evaluates to "$foo[1]" "$foo[2]" ..."

for associative arrays, [*] or [@] evaluate to all the values, in no particular order. note that this does not substitute the keys; see the documentation for the k flag under Parameter Expansion Flags in zshexpn(1) for complete details. when an array parameter is referenced as $name (with no subscript) it evaluates to $name[*], unless the KSH_ARRAYS option is set, in which case it evaluates to ${name[0]} โ€” and for an associative array, that means the value of the key 0, which may not exist even if there are values for other keys. awkward but true ๐Ÿ˜ญ

a subscript of the form [exp1,exp2] selects all elements in the range exp1 to exp2, inclusive. (associative arrays are unordered, and so do not support ranges. sorry bestie.) if one of the subscripts evaluates to a negative number, say -n, then the *n*th element from the end of the array is used. thus $foo[-3] is the third element from the end of the array foo, and $foo[1,-1] is the same as $foo[*]. negative indexing is THAT girl ๐Ÿ’…

subscripting may also be performed on non-array values, in which case the subscripts specify a substring to be extracted. for example, if FOO is set to foobar, then echo $FOO[2,5] prints ooba. note that some forms of subscripting described below perform pattern matching, and in that case the substring extends from the start of the match of the first subscript to the end of the match of the second subscript. example:

string="abcdefghijklm"
print ${string[(r)d?,(r)h?]}

prints defghi. this is an obvious generalisation of the rule for single-character matches. for a single subscript, only a single character is referenced (not the range of characters covered by the match). she's precise, she's iconic, she's done with part one ๐Ÿฆ‹


(part 1 done โ€” more parts are literally coming, don't go anywhere)

Quick note before we move on, bestie โ€” in substring ops the second subscript gets treated differently by the r and R flags: r takes the shortest match as the length, R takes the longest match. So with r a * at the end is literally doing nothing (redundant, we love an understudy), while with R it matches the whole rest of the string. ๐Ÿ’… And this doesn't change anything in the single-subscript case, because there the length of the match is irrelevant. Slay.


๐ŸŽ€ Array Element Assignment ๐ŸŽ€

A subscript can show up on the left side of an assignment, like this:

name[exp]=value

In this form, whatever element or range exp points at gets replaced by the expression on the right side. You can create an array (but not an associative array, bestie, know the difference โœจ) by assigning to a range or an element. Arrays do not nest โ€” so if you assign a parenthesized list of values to an element or a range, that changes the number of elements in the array and shifts the other elements around to make room. (This is not supported for associative arrays, sorry ๐Ÿซถ)

This syntax also works as an argument to the typeset command:

typeset "name[exp]"=value

But heads up: in this case the value may not be a parenthesized list โ€” with typeset you can only make single-element assignments. Also, the quotes are genuinely necessary here so the brackets don't get read as filename generation operators. (Related: the noglob precommand modifier could be used instead. Options, we love options ๐Ÿ’–)

To delete an element of an ordinary array, assign () to that element. To delete an element of an associative array, use the unset command:

unset "name[exp]"

โœจ Subscript Flags โœจ

Okay so here's the cute part: if the opening bracket โ€” or the comma in a range โ€” in any subscript expression is directly followed by an opening parenthesis, then everything up to the matching closing paren counts as a list of flags. Like name[(flags)exp]. Iconic.

The flags s, n and b take an argument; the delimiter is shown below as :, but literally any character works โ€” or the matching pairs (...), {...}, [...], or <...>. โš ๏ธ One little catch: <...> can only be used if the subscript is inside a double quoted expression or a parameter substitution wrapped in braces, otherwise the expression gets interpreted as a redirection. Not that, bestie.

The flags we currently understand are:

  • w โ€” If the parameter you're subscripting is a scalar, this flag makes subscripting work on words instead of characters. Default word separator is whitespace. When you combine it with i or I, the effect is to give you the index of the first character of the first/last word that matches the given pattern; note that a failed match in this case always yields 0. ๐Ÿซถ
  • s:string: โ€” This gives the string that separates words (for use with the w flag). The delimiter character : is arbitrary; see above. ๐ŸŽ€
  • p โ€” Recognize the same escape sequences as the print builtin, applied to the string argument of a subsequent s flag. Big brain energy.
  • f โ€” If the parameter subscripted is a scalar, this makes subscripting work on lines instead of characters, i.e. elements separated by newlines. It's shorthand for pws:\n:. ๐ŸŒธ
  • r โ€” Reverse subscripting, my beloved: if this flag is given, exp is taken as a pattern and the result is the first matching array element, substring, or word (depending on whether the parameter is an array, a scalar, or a scalar with the w flag given, respectively). The subscript used is the number of the matching element, so pairs of subscripts such as $foo[(r)??,3] and $foo[(r)??,(r)f*] are possible if the parameter is not an associative array. If the parameter is an associative array, only the value part of each pair gets compared to the pattern, and the result is that value. ๐Ÿฆ‹

If a search through an ordinary array failed, the search sets the subscript to one past the end of the array โ€” which means ${array[(r)pattern]} will substitute the empty string. So the success of a search can be tested with the (i) flag, for example (assuming the option KSH_ARRAYS is not in effect):

[[ ${array[(i)pattern]} -le ${#array} ]]

If KSH_ARRAYS is in effect, replace the -le with -lt. ๐Ÿ˜ญ

  • R โ€” Like r, but gives the last match. For associative arrays, gives all possible matches. May be used for assigning to ordinary array elements, but not for assigning to associative arrays. On failure, for normal arrays this has the effect of returning the element corresponding to subscript 0; that's empty unless one of the options KSH_ARRAYS or KSH_ZERO_SUBSCRIPT is in effect. ๐Ÿ’€

Note that in subscripts with both r and R, pattern characters are active even if they were substituted for a parameter (regardless of the setting of GLOB_SUBST, which controls this feature in normal pattern matching). The flag e can be added to inhibit pattern matching. But since that flag doesn't inhibit other forms of substitution, care is still required โ€” using a parameter to hold the key has the desired effect:

key2='original key'
print ${array[(Re)$key2]}
  • i โ€” Like r, but gives the index of the match instead; this may not be combined with a second argument. On the left side of an assignment, it behaves like r. For associative arrays, the key part of each pair is compared to the pattern, and the first matching key found is the result. On failure it substitutes the length of the array plus one, as discussed under r, or the empty string for an associative array. ๐Ÿ”ฅ
Note: although i may be applied to a scalar substitution to find the offset of a substring, the results are likely to be misleading when searching within substitutions that yield an empty string, or when searching for the empty substring. Don't say I didn't warn you ๐Ÿ™ˆ
  • I โ€” Like i, but gives the index of the last match, or all possible matching keys in an associative array. On failure it substitutes 0, or the empty string for an associative array. This flag is genuinely the best when testing for values or keys that don't exist. ๐Ÿ‘‘
Note: if the option KSH_ARRAYS is in effect and no match is found, the result is indistinguishable from the case where the first element of the array matches. Awkward. ๐Ÿ˜ฌ
  • k โ€” If used in a subscript on an associative array, this flag makes the keys be interpreted as patterns, and returns the value for the first key found where exp is matched by the key. Note this could be any such key, since no ordering of associative arrays is defined. This flag does not work on the left side of an assignment to an associative array element. If used on another type of parameter, it behaves like r. ๐Ÿ’ซ
  • K โ€” On an associative array this is like k, but returns all values where exp is matched by the keys. On other types of parameters it has the same effect as R. ๐ŸŒˆ
  • n:expr: โ€” If combined with r, R, i or I, makes them give the nth or nth-from-last match (if expr evaluates to n). This flag is ignored when the array is associative. The delimiter character : is arbitrary; see above. โญ
  • b:expr: โ€” If combined with r, R, i or I, makes them begin at the nth or nth-from-last element, word, or character (if expr evaluates to n). Also ignored when the array is associative. Delimiter character : is arbitrary; see above. ๐Ÿ’œ
  • e โ€” This flag causes any pattern matching that would be performed on the subscript to use plain string matching instead. Hence ${array[(re)*]} matches only the array element whose value is *. Note that other forms of substitution, like parameter substitution, are not inhibited. ๐Ÿงš

This flag can also be used to force * or @ to be interpreted as a single key rather than as a reference to all values. It may be used for either purpose on the left side of an assignment. ๐Ÿ’…

See Parameter Expansion Flags (zshexpn(1)) for extra ways to manipulate the results of array subscripting. There's always more lore, iykyk.


๐Ÿฆ‹ Subscript Parsing ๐Ÿฆ‹

This discussion applies mainly to associative array key strings and to patterns used for reverse subscripting (the r, R, i, etc. flags), but it may also affect parameter substitutions that appear as part of an arithmetic expression in an ordinary subscript. Stay with me, bestie.

To dodge subscript parsing limitations when assigning to associative array elements, use the append syntax:

aa+=('key with "*strange*" characters' 'value string')

The basic rule to remember when writing a subscript expression is that all text between the opening [ and the closing ] is interpreted as if it were inside double quotes (see zshmisc(1)). But โ€” unlike double quotes, which normally can't nest โ€” subscript expressions may appear inside double-quoted strings, or inside other subscript expressions (or both!!), so the rules have two important differences. ๐Ÿ˜ค

Difference #1: brackets ([ and ]) must appear as balanced pairs inside a subscript expression unless they're preceded by a backslash (\). So inside a subscript expression (and unlike true double-quoting), the sequence \[ becomes [, and likewise \] becomes ]. This applies even when a backslash wouldn't normally be required; for example, the pattern [^[] (to match any character other than an open bracket) should be written [^\[] in a reverse-subscript pattern. However, note that \[^\[\] and even \[^[] mean the same thing, because backslashes are always stripped when they appear before brackets! Wild, I know. ๐Ÿ’€

The same rule applies to parentheses (( and )) and braces ({ and }): they must appear either in balanced pairs or preceded by a backslash, and backslashes that protect parentheses or braces get removed during parsing. Why? Because parameter expansions may be surrounded by balanced braces, and subscript flags are introduced by balanced parentheses. It's giving structural integrity. ๐ŸŽ€

Difference #2: a double-quote (") may appear as part of a subscript expression without being preceded by a backslash โ€” which means the two characters \" remain as two characters in the subscript (whereas in true double-quoting, \" becomes "). But because of standard shell quoting rules, any double-quotes that do appear must still occur in balanced pairs unless preceded by a backslash. Which makes it harder to write a subscript expression containing an odd number of double-quote characters ๐Ÿ˜ญ โ€” but the reason for this difference is so that when a subscript expression appears inside true double-quotes, you can still write \" (rather than \\\") for ". And that's the whole vibe. ๐Ÿซถ

okay so if you ever need an odd number of double quotes as a key in an assignment, the move is: use the typeset builtin plus an enclosing pair of double quotes ๐ŸŽ€ and to read that key's value back, double quotes again, bestie:

typeset -A aa
typeset "aa[one\"two\"three\"quotes]"=QQQ
print "$aa[one\"two\"three\"quotes]"

It is so important to note that the quoting rules do not change when a parameter expansion with a subscript gets nested inside another subscript expression ๐Ÿ’… like, you do not need extra backslashes inside the inner subscript expression โ€” they get removed only once, from the innermost subscript outwards. Also, parameters get expanded from the innermost subscript first, as each expansion is encountered left to right in the outer expression โœจ


A further complication (ugh, I know ๐Ÿ˜ญ) comes from a way in which subscript parsing is not different from double quote parsing. Just like in true double-quoting, the sequences \* and \@ stay as two characters when they show up in a subscript expression. So to use a literal * or @ as an associative array key, you gotta use the e flag:

typeset -A aa
aa[(e)*]=star
print $aa[(e)*]

One last detail you gotta consider when reverse subscripting is happening ๐Ÿ”ฅ parameters appearing in the subscript expression get expanded first, and then the complete expression is interpreted as a pattern. Two effects from this:

  • first, parameters behave as if GLOB_SUBST were on (and it cannot be turned off);
  • second, backslashes are interpreted twice โ€” once when parsing the array subscript, and again when parsing the pattern.

In a reverse subscript, you need four backslashes to make a single backslash match literally in the pattern ๐Ÿ˜ตโ€๐Ÿ’ซ For complex patterns, it's often easiest to assign the pattern you want to a parameter and then refer to that parameter in the subscript, because then the backslashes, brackets, parentheses, etc. are seen only when the complete expression is converted to a pattern. And if you wanna match the value of a parameter literally in a reverse subscript rather than as a pattern, use ${(q)name} (see zshexpn(1)) to quote the expanded value ๐Ÿซถ

Real talk: the k and K flags are reverse subscripting for an ordinary array, but they are not reverse subscripting for an associative array! (For an associative array, the keys in the array itself are what get interpreted as patterns by those flags; the subscript is a plain string in that case.) ๐Ÿ’€

One final note, and it's not even directly about subscripting: the numeric names of positional parameters (described below) are parsed specially, so for example $2foo is equivalent to ${2}foo. Therefore, to use subscript syntax to extract a substring from a positional parameter, the expansion must be surrounded by braces โ€” for example, ${2[3,5]} evaluates to the third through fifth characters of the second positional parameter, but $2[3,5] is the entire second parameter concatenated with the filename generation pattern [3,5] ๐Ÿ™ˆ


๐ŸŽฏ POSITIONAL PARAMETERS

The positional parameters are your backstage pass to the command-line arguments of a shell function, a shell script, or the shell itself ๐ŸŽค see the section Invocation, and also the section Functions. The parameter n, where n is a number, is the *n*th positional parameter. The parameter $0 is a special case โ€” see the section Parameters Set By The Shell.

The parameters *, @ and argv are arrays containing all the positional parameters, so $argv[n], etc., is equivalent to just $n โœจ Note that the options KSH_ARRAYS or KSH_ZERO_SUBSCRIPT apply to these arrays too, so with either of those options set, ${argv[0]} is equivalent to $1 and so on ๐Ÿ‘‘

Positional parameters can be changed after the shell or function starts, by using the set builtin, by assigning to the argv array, or by direct assignment of the form n=value where n is the number of the positional parameter you wanna change. This also creates (with empty values) any of the positions from 1 to n that don't already have values ๐ŸŽ€ And note that, because positional parameters form an array, an array assignment of the form n=(value ...) is allowed, and it has the effect of shifting all the values at positions greater than n by as many positions as necessary to accommodate the new values ๐Ÿ’ซ

๐Ÿ  LOCAL PARAMETERS

Shell function executions delimit scopes for shell parameters โ€” and yeah, parameters are dynamically scoped ๐ŸŒธ The typeset builtin, and its alternative forms declare, integer, local and readonly (but not export), can be used to declare a parameter as being local to the innermost scope.

When a parameter is read or assigned to, the innermost existing parameter of that name is used (that is, the local parameter hides any less-local parameter) ๐Ÿ™ˆ However, assigning to a non-existent parameter, or declaring a new parameter with export, causes it to be created in the outermost scope.

Local parameters disappear when their scope ends. unset can be used to delete a parameter while it's still in scope; any outer parameter of the same name stays hidden ๐Ÿ‘€

Special parameters may also be made local; they retain their special attributes unless either the existing or the newly-created parameter has the -h (hide) attribute. This may have unexpected effects: there is no default value, so if there's no assignment at the point the variable is made local, it will be set to an empty value (or zero in the case of integers) ๐Ÿ˜ญ The following:

typeset PATH=/new/directory:$PATH

is valid for temporarily allowing the shell, or programmes called from it, to find the programs in /new/directory inside a function โœจ

ngl, the restriction in older versions of zsh that local parameters were never exported? That's been removed ๐Ÿ’…

๐Ÿ‘‘ PARAMETERS SET BY THE SHELL

In the parameter lists that follow, the mark <S> means the parameter is special โญ And <Z> means the parameter does not exist when the shell initializes in sh or ksh emulation mode.

The parameters !, #, *, -, ?, @, $, ARGC, HISTCMD, LINENO, PPID, status, TTYIDLE, zsh_eval_context, ZSH_EVAL_CONTEXT, and ZSH_SUBSHELL are read-only and thus cannot be restored by the user, so they are not output by typeset -p. This also applies to many read-only parameters loaded from modules ๐Ÿงš

The following parameters are automatically set by the shell ๐ŸŽ€

  • ! <S> โ€” The process ID of the last command started in the background with &, put into the background with the bg builtin, or spawned with coproc.
  • # <S> โ€” The number of positional parameters in decimal. Note that some confusion may occur with the syntax $#param, which substitutes the length of param. Use ${#} to resolve ambiguities. In particular, the sequence $#-... in an arithmetic expression is interpreted as the length of the parameter -, q.v.
  • ARGC <S> <Z> โ€” Same as #.
  • $ <S> โ€” The process ID of this shell, set when the shell initializes. Processes forked from the shell without executing a new program, such as command substitutions and commands grouped with (...), are subshells that duplicate the current shell, and thus substitute the same value for $$ as their parent shell.
  • - <S> โ€” Flags supplied to the shell on invocation or by the set or setopt commands.
  • * <S> โ€” An array containing the positional parameters.
  • argv <S> <Z> โ€” Same as *. Assigning to argv changes the local positional parameters, but argv is not itself a local parameter. Deleting argv with unset in any function deletes it everywhere, although only the innermost positional parameter array is deleted (so * and @ in other scopes are not affected).
  • @ <S> โ€” Same as argv[@], even when argv is not set.
  • ? <S> โ€” The exit status returned by the last command.
  • 0 <S> โ€” The name used to invoke the current shell, or as set by the -c command line option upon invocation. If the FUNCTION_ARGZERO option is set, $0 is set upon entry to a shell function to the name of the function, and upon entry to a sourced script to the name of the script, and reset to its previous value when the function or script returns.
  • status <S> <Z> โ€” Same as ?.
  • pipestatus <S> <Z> โ€” An array containing the exit statuses returned by all commands in the last pipeline.
  • _ <S> โ€” The last argument of the previous command. Also, this parameter is set in the environment of every command executed to the full pathname of the command.
  • CPUTYPE โ€” The machine type (microprocessor class or machine model), as determined at run time.
  • EGID <S> โ€” The effective group ID of the shell process. If you have sufficient privileges, you may change the effective group ID of the shell process by assigning to this parameter. Also (assuming sufficient privileges), you may start a single command with a different effective group ID by (EGID=gid; command)

If this is made local, it is not implicitly set to 0, but may be explicitly set locally.

  • EUID <S> โ€” The effective user ID of the shell process. If you have sufficient privileges, you may change the effective user ID of the shell process by assigning to this parameter. Also (assuming sufficient privileges), you may start a single command with a different effective user ID by (EUID=uid; command)

If this is made local, it is not implicitly set to 0, but may be explicitly set locally.

  • ERRNO <S> โ€” The value of errno (see errno(3)) as set by the most recently failed system call. This value is system dependent and is intended for debugging purposes. It's also useful with the zsh/system module, which lets the number be turned into a name or message ๐Ÿงš

To use this parameter, it must first be assigned a value (typically 0 (zero)). It's initially unset for scripting compatibility.

  • FUNCNEST <S> โ€” Integer. If greater than or equal to zero, the maximum nesting depth of shell functions. When it's exceeded, an error is raised at the point where a function is called. The default value is determined when the shell is configured, but is typically 500. Increasing the value increases the danger of a runaway function recursion causing the shell to crash ๐Ÿ’€ Setting a negative value turns off the check.

GID <S>

The real group ID of the shell process, bestie. If you've got sufficient privileges, you can literally change the group ID of the shell process by assigning to this parameter. And also โ€” assuming sufficient privileges again โ€” you can start a single command under a different group ID with (GID=gid; command) โœจ

If this one is made local, it is not implicitly set to 0, but it may be explicitly set locally. Noted ๐Ÿ’…

HISTCMD

The current history event number in an interactive shell โ€” in other words, the event number for the command that caused $HISTCMD to be read. If the current history event modifies the history, HISTCMD changes to the new maximum history event number. Sneaky but valid ๐Ÿซถ

HOST

The current hostname. That's it, that's the whole vibe ๐ŸŽ€

LINENO <S>

The line number of the current line within the current script, sourced file, or shell function being executed โ€” whichever was started most recently. Lowkey important caveat: in the case of shell functions, the line number refers to the function as it appeared in the original definition, not necessarily as displayed by the functions builtin. So don't come for it when the numbers don't match your scroll position ๐Ÿ˜ญ

LOGNAME

If the corresponding variable is not set in the environment of the shell, it's initialized to the login name corresponding to the current login session. This parameter is exported by default, but that can be disabled using the typeset builtin. The value is set to the string returned by the getlogin(3) system call if that's available. fr fr ๐ŸŒธ

MACHTYPE

The machine type (microprocessor class or machine model), as determined at compile time. It's giving "who am I, really" energy ๐Ÿ‘‘

OLDPWD

The previous working directory. This is set when the shell initializes and whenever the directory changes. The nostalgic one ๐Ÿฅฒ

OPTARG <S>

The value of the last option argument processed by the getopts command.

OPTIND <S>

The index of the last option argument processed by the getopts command. These two are a package deal, iykyk ๐ŸŽ

OSTYPE

The operating system, as determined at compile time.

PPID <S>

The process ID of the parent of the shell, set when the shell initializes. As with $$, the value does not change in subshells created as a duplicate of the current shell. Main character stays main character ๐Ÿ’€

PWD

The present working directory. This is set when the shell initializes and whenever the directory changes โ€” the present-tense sibling of OLDPWD ๐Ÿฆ‹

RANDOM <S>

A pseudo-random integer from 0 to 32767, newly generated each time this parameter is referenced. The random number generator can be seeded by assigning a numeric value to RANDOM. Obsessed with the chaos ๐Ÿ”ฅ

The values of RANDOM form an intentionally-repeatable pseudo-random sequence, so subshells that reference RANDOM will result in identical pseudo-random values unless the value of RANDOM is referenced or seeded in the parent shell in between subshell invocations. Yes, this is on purpose. No, it's not a bug ๐ŸŒˆ

SECONDS <S>

The number of seconds since shell invocation. If this parameter is assigned a value, then the value returned upon reference will be the value that was assigned plus the number of seconds since the assignment. Time math, slay โฑ๏ธ

Unlike other special parameters, the type of the SECONDS parameter can be changed using the typeset command. The type may be changed only to one of the floating point types or back to integer. For example, typeset -F SECONDS causes the value to be reported as a floating point number. The value is available to microsecond accuracy, although the shell may show more or fewer digits depending on the use of typeset. See the documentation for the builtin typeset in zshbuiltins(1) for more details. ๐Ÿ’–

SHLVL <S>

Incremented by one each time a new shell is started. Shell inception, basically ๐ŸŒ€

signals

An array containing the names of the signals. Note that with the standard zsh numbering of array indices, where the first element has index 1, the signals are offset by 1 from the signal number used by the operating system. For example, on typical Unix-like systems HUP is signal number 1, but is referred to as $signals[2]. This is because of EXIT at position 1 in the array, which is used internally by zsh but is not known to the operating system. ๐Ÿ™ˆ

On many systems there is a block of reserved or unused signal numbers before the POSIX real-time signals, so the array index can't be used as an accurate indicator of their signal number. Use, for example, kill -l SIGRTMIN instead. Don't let the index lie to you ๐Ÿ’€

TRY_BLOCK_ERROR <S>

In an always block, indicates whether the preceding list of code caused an error. The value is 1 to indicate an error, 0 otherwise. It may be reset, clearing the error condition. See Complex Commands in zshmisc(1).

TRY_BLOCK_INTERRUPT <S>

This variable works in a similar way to TRY_BLOCK_ERROR, but represents the status of an interrupt from the signal SIGINT, which typically comes from the keyboard when the user types Ctrl+C. If set to 0, any such interrupt will be reset; otherwise, the interrupt is propagated after the always block. ๐Ÿซถ

Heads up, bestie: it is possible that an interrupt arrives during the execution of the always block โ€” and this interrupt is also propagated. Timing is everything, and sometimes the timing is rude ๐Ÿ˜ญ

TTY

The name of the tty associated with the shell, if any.

TTYIDLE <S>

The idle time of the tty associated with the shell in seconds, or -1 if there is no such tty. Touch grass metric, essentially ๐ŸŒฑ

UID <S>

The real user ID of the shell process. If you have sufficient privileges, you may change the user ID of the shell by assigning to this parameter. Also (assuming sufficient privileges), you may start a single command under a different user ID by (UID=uid; command) โœจ

If this is made local, it is not implicitly set to 0, but may be explicitly set locally. Same policy as GID, we keep it consistent ๐Ÿ’…

USERNAME <S>

The username corresponding to the real user ID of the shell process. If you have sufficient privileges, you may change the username (and also the user ID and group ID) of the shell by assigning to this parameter. Also (assuming sufficient privileges), you may start a single command under a different username (and user ID and group ID) by (USERNAME=username; command). It's giving identity crisis but make it authorized ๐Ÿ‘‘

VENDOR

The vendor, as determined at compile time.

zsh_eval_context <S> <Z> (ZSH_EVAL_CONTEXT <S>)

An array (colon-separated list) indicating the context of shell code that is being run. Each time a piece of shell code that is stored within the shell is executed, a string is temporarily appended to the array to indicate the type of operation that is being performed. Read in order, the array gives an indication of the stack of operations being performed, with the most immediate context last. The receipts, basically ๐Ÿงพ

Note that the variable does not give information on syntactic context such as pipelines or subshells. Use $ZSH_SUBSHELL to detect subshells. Different question, different tool ๐Ÿฆ‹

The context is one of the following:

  • cmdarg โ€” code specified by the -c option to the command line that invoked the shell.
  • cmdsubst โ€” command substitution using the `...` or $(...) construct.
  • equalsubst โ€” file substitution using the =(...) construct.
  • eval โ€” code executed by the eval builtin.
  • evalautofunc โ€” code executed with the KSH_AUTOLOAD mechanism in order to define an autoloaded function.
  • fc โ€” code from the shell history executed by the -e option to the fc builtin.
  • file โ€” lines of code being read directly from a file, for example by the source builtin.
  • filecode โ€” lines of code being read from a .zwc file instead of directly from the source file.
  • globqual โ€” code executed by the e or + glob qualifier.
  • globsort โ€” code executed to order files by the o glob qualifier.
  • insubst โ€” file substitution using the <(...) construct.
  • loadautofunc โ€” code read directly from a file to define an autoloaded function.
  • outsubst โ€” file substitution using the >(...) construct.
  • sched โ€” code executed by the sched builtin.
  • shfunc โ€” a shell function.
  • stty โ€” code passed to stty by the STTY environment variable. Normally this is passed directly to the system's stty command, so this value is unlikely to be seen in practice.
  • style โ€” code executed as part of a style retrieved by the zstyle builtin from the zsh/zutil module.
  • toplevel โ€” the highest execution level of a script or interactive shell.
  • trap โ€” code executed as a trap defined by the trap builtin. Traps defined as functions have the context shfunc. As traps are asynchronous they may have a different hierarchy from other code.
  • zpty โ€” code executed by the zpty builtin from the zsh/zpty module.
  • zregexparse-guard โ€” code executed as a guard by the zregexparse command from the zsh/zutil module.
  • zregexparse-action โ€” code executed as an action by the zregexparse command from the zsh/zutil module.

ZSH_ARGZERO

If zsh was invoked to run a script, this is the name of the script. Otherwise, it is the name used to invoke the current shell. This is the same as the value of $0 when the POSIX_ARGZERO option is set, but is always available. Reliable queen ๐Ÿ‘‘

ZSH_EXECUTION_STRING

If the shell was started with the option -c, this contains the argument passed to the option. Otherwise it is not set.

ZSH_NAME

Expands to the basename of the command used to invoke this instance of zsh. Just the name, no path drama ๐ŸŽ€

ZSH_PATCHLEVEL

The output of git describe --tags --long for the zsh repository used to build the shell. This is most useful in order to keep track of versions of the shell during development between releases; hence most users should not use it and should instead rely on $ZSH_VERSION. Devs only, respectfully ๐Ÿ™ˆ

zsh_scheduled_events

See the section The zsh/sched Module in zshmodules(1).

ZSH_SCRIPT

If zsh was invoked to run a script, this is the name of the script, otherwise it is unset. Simple as that ๐ŸŒธ

  • ZSH_SUBSHELL โ€” readonly integer, bestie, you cannot touch this one. Starts at zero and gets bumped by one every single time the shell forks to make a subshell for running code. So (print $ZSH_SUBSHELL) and print $(print $ZSH_SUBSHELL) both spit out 1, but ( (print $ZSH_SUBSHELL) ) gives you 2 โ€” nesting is real ๐Ÿ’…
  • ZSH_VERSION โ€” literally just the version number of the zsh release you're running. That's it, that's the whole vibe ๐ŸŽ€

โœจ PARAMETERS USED BY THE SHELL โœจ

Okay so these are the parameters the shell itself actually uses โ€” like, they're not just sitting there being cute, the shell is actively reading them. Quick legend reminder because we love a key: <S> means the parameter is special, and <Z> means the parameter doesn't exist when the shell initializes in sh or ksh emulation mode. ๐Ÿซถ

So when you've got two parameters with the same name but one's upper and one's lowercase โ€” think path and PATH โ€” the lowercase one is the array and the uppercase one is a scalar with all the array's elements joined up by colons. They're basically tied parameters like the ones you make with typeset -T. The colon-separated version is your girl for exporting to the environment, and the array version is way easier to actually mess with inside the shell. And heads up: unsetting either one of the pair unsettings the other ๐Ÿ˜ญ they keep their special properties when you recreate them, and recreating one recreates the other. Package deal, no cap.

  • ARGV0 โ€” if you export it, its value becomes the argv[0] of external commands. Classic move is stuff like ARGV0=emacs nethack โ€” iconic little identity crisis for your process ๐ŸŽญ
  • BAUD โ€” the rate in bits per second at which data reaches your terminal. The line editor uses this to compensate for a slow terminal by delaying updates to the display until it actually needs them. If the parameter is unset, or its value is zero, the compensation mechanism is just off. Not set by default, so don't come for her.

This one's genuinely worth setting in some situations, like slow modems dialing into a communications server, or on a slow wide area network. For best performance, set it to the baud rate of the slowest part of the link. Slay, but slowly ๐ŸŒ

  • cdpath <S> <Z> (CDPATH <S>) โ€” an array (aka a colon-separated list) of directories that specifies the search path for the cd command.
  • COLUMNS <S> โ€” how many columns your terminal session has. Used for printing select lists and for the line editor. She's all about the width ๐Ÿ’…
  • CORRECT_IGNORE โ€” if set, it's treated as a pattern during spelling correction, and any potential correction that matches the pattern gets ignored. Example: if the value is _* then completion functions โ€” which by convention have names starting with _ โ€” will never be offered as spelling corrections. One thing though: the pattern does not apply to the correction of file names, like the kind CORRECT_ALL does. So with that same example, files in the current directory that begin with _ would still get completed. Careful bestie ๐Ÿ™ˆ
  • CORRECT_IGNORE_FILE โ€” if set, it's treated as a pattern during spelling correction of file names. Any file name matching the pattern is never offered as a correction. For example, if the value is .* then dot file names never get offered as spelling corrections. Super useful with the CORRECT_ALL option โœจ
  • DIRSTACKSIZE โ€” the maximum size of the directory stack. By default there's no limit at all. If the stack gets bigger than this, it gets truncated automatically. Great with the AUTO_PUSHD option ๐ŸŽ€
  • ENV โ€” if the ENV environment variable is set when zsh is invoked as sh or ksh, then $ENV is sourced after the profile scripts. Its value gets subjected to parameter expansion, command substitution, and arithmetic expansion before it's interpreted as a pathname. Note that ENV is not used unless the shell is interactive and zsh is emulating sh or ksh. Conditional queen ๐Ÿ‘‘
  • FCEDIT โ€” the default editor for the fc builtin. If FCEDIT isn't set, then EDITOR gets used; if that's not set either, a builtin default is used, usually vi. The fallback chain is giving very prepared ๐Ÿซถ
  • fignore <S> <Z> (FIGNORE <S>) โ€” an array (colon-separated list) holding the suffixes of files to be ignored during filename completion. But plot twist: if completion only generates files with suffixes in this list, then those files get completed anyway. She's stubborn but fair ๐Ÿ˜Œ
  • fpath <S> <Z> (FPATH <S>) โ€” an array (colon-separated list) of directories specifying the search path for function definitions. This path gets searched when a function with the -u attribute is referenced. If an executable file is found, it's read and executed in the current environment. Very demure, very in-place ๐Ÿ’–
  • histchars <S> โ€” three characters used by the shell's history and lexical analysis mechanism:
    • the first character signals the start of a history expansion (default !)
    • the second character signals the start of a quick history substitution (default ^)
    • the third character is the comment character (default #)

These characters must be in the ASCII character set โ€” any attempt to set histchars to characters with a locale-dependent meaning gets rejected with an error message. No cap, it'll just refuse you ๐Ÿ’€

  • HISTCHARS <S> <Z> โ€” same as histchars. Also (Deprecated.) so like, she's still here but she's retired ๐Ÿ‘ต
  • HISTFILE โ€” the file your history gets saved into when an interactive shell exits. If it's unset, the history is simply not saved. Tragic, honestly ๐Ÿ˜ญ
  • HISTORY_IGNORE โ€” if set, it's treated as a pattern at the time history files are written, and any potential history entry matching the pattern gets skipped. For example, if the value is fc * then commands that invoke the interactive history editor never get written to the history file. Clean ๐Ÿงผ

Note that HISTORY_IGNORE defines a single pattern โ€” if you want alternatives, use the (first|second|...) syntax.

Compare the HIST_NO_STORE option or the zshaddhistory hook, either of which would prevent such commands from being added to the interactive history at all. If you want to use HISTORY_IGNORE to stop history being added in the first place, you can define this hook:

zshaddhistory() {
  emulate -L zsh
  ## uncomment if HISTORY_IGNORE
  ## should use EXTENDED_GLOB syntax
  # setopt extendedglob
  [[ $1 != ${~HISTORY_IGNORE} ]]
}
  • HISTSIZE <S> โ€” the maximum number of events stored in the internal history list. If you're using the HIST_EXPIRE_DUPS_FIRST option, setting this larger than the SAVEHIST size gives you the difference as a cushion for saving duplicated history events. Comfy buffer energy โœจ

Also: if this is made local, it is not implicitly set to 0 โ€” but you can explicitly set it locally if you want.

  • HOME <S> โ€” the default argument for the cd command. Not set automatically by the shell in sh, ksh or csh emulation, but it's typically hanging out in the environment anyway, and if it does become set, it has its usual special behaviour. Home sweet home ๐Ÿ 
  • IFS <S> โ€” internal field separators (by default space, tab, newline and NUL) used to separate words resulting from command or parameter expansion, and words read by the read builtin. Any characters from the set space, tab and newline that appear in IFS are called IFS white space. One or more IFS white space characters, or one non-IFS white space character together with any adjacent IFS white space character, delimit a field. And if an IFS white space character appears twice consecutively in IFS, that character is treated as if it were not an IFS white space character. Delulu but consistent ๐Ÿ’…

If the parameter is unset, the default is used โ€” and note that this has a different effect from setting the parameter to an empty string. Important distinction, ngl.

If the MULTIBYTE option is on and IFS contains invalid characters in the current locale, it gets reset to the default. Safety net ๐ŸŒธ

  • KEYBOARD_HACK โ€” this variable defines a character to be removed from the end of the command line before interpreting it (interactive shells only). It's meant to fix that problem where keys are placed annoyingly close to return, and it replaces the SUNKEYBOARDHACK option which only did this for backquotes. If the chosen character is one of singlequote, doublequote or backquote, there must also be an odd number of them on the command line for the last one to be removed. Rules are rules ๐ŸŽ€

For backward compatibility: if the SUNKEYBOARDHACK option is explicitly set, the value of KEYBOARD_HACK reverts to backquote. If the option is explicitly unset, this variable is set to empty.

  • KEYTIMEOUT โ€” the time the shell waits, in hundredths of a second, for another key to be pressed when reading bound multi-character sequences. Patience is a virtue โณ
  • LANG <S> โ€” determines the locale category for any category not specifically selected via a variable starting with LC_.
  • LC_ALL <S> โ€” overrides the value of the LANG variable and the value of any of the other variables starting with LC_. She's the final boss ๐Ÿ‘‘
  • LC_COLLATE <S> โ€” determines the locale category for character collation info within ranges in glob brackets and for sorting. Alphabetize responsibly ๐Ÿ”ค
  • LC_CTYPE <S> โ€” determines the locale category for character handling functions. If the MULTIBYTE option is in effect, this variable or LANG should contain a value reflecting the character set in use โ€” even if it's a single-byte character set โ€” unless only the 7-bit subset (ASCII) is used. For example, if the character set is ISO-8859-1, a suitable value might be en_US.iso88591 (certain Linux distributions) or en_US.ISO8859-1 (MacOS). Know your encoding, bestie ๐Ÿงš
  • LC_MESSAGES <S> โ€” determines the language in which messages should be written. Note that zsh does not use message catalogs. Just so you know ๐Ÿ’ฌ
  • LC_NUMERIC <S> โ€” affects the decimal point character and thousands separator character for the formatted input/output functions and string conversion functions. Big note: zsh ignores this setting when parsing floating point mathematical expressions. Math stays math ๐Ÿ”ฅ
  • LC_TIME <S> โ€” determines the locale category for date and time formatting in prompt escape sequences. Clock girl behaviour ๐Ÿ•
  • LINES <S> โ€” the number of lines for this terminal session. Used for printing select lists and for the line editor. Height check โœจ
  • LISTMAX โ€” in the line editor, this is how many matches get listed without asking first โœจ. Negative value? Then the list gets shown if it spans at most that many lines (absolute value, babes). Set it to zero and the shell only asks if the top of the listing would scroll off the screen. Very demure, very mindful.
  • MAIL โ€” if this one's set and mailpath is not set, the shell goes looking for mail in the file you specified ๐Ÿ’Œ.
  • MAILCHECK โ€” the interval, in seconds, between checks for new mail. Your lil mail-checking heartbeat โฐ.
  • mailpath <S> <Z> (MAILPATH <S>) โ€” an array (colon-separated list) of filenames to check for new mail ๐Ÿ“ฌ. Each filename can be followed by a ? and a message that will be printed. That message undergoes parameter expansion, command substitution and arithmetic expansion with the variable $_ defined as the name of the file that has changed. The default message is You have new mail. And plot twist: if an element is a directory instead of a file, the shell will recursively check every file in every subdirectory of the element ๐Ÿ‘‘
  • manpath <S> <Z> (MANPATH <S> <Z>) โ€” an array (colon-separated list) whose value the shell itself does not use. Lowkey useless to zsh, highkey useful to you, because setting it also sets MANPATH, and vice versa. Bestie maths ๐Ÿงฎ.
  • match
  • mbegin
  • mend โ€” arrays set by the shell when the b globbing flag is used in pattern matches. See the subsection Globbing flags in the documentation for Filename Generation in zshexpn(1) ๐Ÿฆ‹.
  • MATCH
  • MBEGIN
  • MEND โ€” set by the shell when the m globbing flag is used in pattern matches. Same deal: see the subsection Globbing flags in the documentation for Filename Generation in zshexpn(1) ๐ŸŒธ.
  • module_path <S> <Z> (MODULE_PATH <S>) โ€” an array (colon-separated list) of directories that zmodload searches for dynamically loadable modules ๐Ÿงฉ. It's initialized to a standard pathname, usually /usr/local/lib/zsh/$ZSH_VERSION. (The /usr/local/lib part varies from installation to installation, jsyk.) For security reasons, any value set in the environment when the shell is started will be ignored โ€” no sneaky env smuggling, periodt ๐Ÿ”’.

These parameters only exist if the installation supports dynamic module loading. No modules, no parameter, no drama.

  • NULLCMD <S> โ€” the command name to assume if a redirection is specified with no command. Defaults to cat ๐Ÿˆ. Want sh/ksh behavior? Change this to :. Want csh-like behavior? Unset this parameter entirely โ€” then the shell will print an error message if null commands are entered. Choose your fighter ๐Ÿ’….
  • path <S> <Z> (PATH <S>) โ€” an array (colon-separated list) of directories to search for commands ๐Ÿ”. When you set this parameter, each directory is scanned and all files found are put in a hash table. Directories named by relative path are not scanned for hashing โ€” noted, moving on ๐Ÿ‘€.
  • POSTEDIT <S> โ€” this string is output whenever the line editor exits. It usually contains termcap strings to reset the terminal, i.e. your little goodbye-and-clean-up ritual ๐ŸŽ€.
  • PROMPT <S> <Z>
  • PROMPT2 <S> <Z>
  • PROMPT3 <S> <Z>
  • PROMPT4 <S> <Z> โ€” same as PS1, PS2, PS3 and PS4, respectively. Aliases, but make it fashion โœจ.
  • prompt <S> <Z> โ€” same as PS1. That's it. That's the entry ๐Ÿซถ.
  • PROMPT_EOL_MARK โ€” when the PROMPT_CR and PROMPT_SP options are set, this parameter customizes how the end of partial lines are shown ๐Ÿ–๏ธ. It undergoes prompt expansion, with the PROMPT_PERCENT option set. If it's not set, the default behavior is equivalent to the value %B%S%#%s%b. Iconic default, ngl.
  • PS1 <S> โ€” the primary prompt string, printed before a command is read ๐Ÿ’–. It undergoes a special form of expansion before being displayed; see EXPANSION OF PROMPT SEQUENCES in zshmisc(1). The default is %m%# โ€” yes, with that trailing space, don't @ me.
  • PS2 <S> โ€” the secondary prompt, printed when the shell needs more information to complete a command ๐Ÿค”. It's expanded in the same way as PS1. Default is %_> , which displays any shell constructs or quotation marks currently being processed. So you can literally see what the shell is still waiting on.
  • PS3 <S> โ€” the selection prompt used within a select loop ๐ŸŽฏ. Expanded in the same way as PS1. The default is ?# .
  • PS4 <S> โ€” the execution trace prompt ๐Ÿ”Ž. Default is +%N:%i> , which displays the name of the current shell structure and the line number within it. In sh or ksh emulation, the default is + .
  • psvar <S> <Z> (PSVAR <S>) โ€” an array (colon-separated list) whose elements can be used in PROMPT strings ๐Ÿฆ‹. Setting psvar also sets PSVAR, and vice versa. Symmetry slay.
  • READNULLCMD <S> โ€” the command name to assume if a single input redirection is specified with no command. Defaults to more ๐Ÿ“–.
  • REPORTMEMORY โ€” if nonnegative, commands whose maximum resident set size (roughly speaking, main memory usage) in kilobytes is greater than this value have timing statistics reported ๐Ÿง . The format used to output statistics is the value of the TIMEFMT parameter, which is the same as for the REPORTTIME variable and the time builtin; note that by default this does not output memory usage. Appending " max RSS %M" to the value of TIMEFMT causes it to output the value that triggered the report. If REPORTTIME is also in use, at most a single report is printed for both triggers. This feature requires the getrusage() system call, commonly supported by modern Unix-like systems.
  • REPORTTIME โ€” if nonnegative, commands whose combined user and system execution times (measured in seconds) are greater than this value have timing statistics printed for them โฑ๏ธ. Output is suppressed for commands executed within the line editor, including completion; commands explicitly marked with the time keyword still cause the summary to be printed in this case.
  • REPLY โ€” this parameter is reserved by convention to pass string values between shell scripts and shell builtins in situations where a function call or redirection are impossible or undesirable ๐Ÿ“จ. The read builtin and the select complex command may set REPLY, and filename generation both sets and examines its value when evaluating certain expressions. Some modules also employ REPLY for similar purposes. It's the group chat of shell parameters, honestly.
  • reply โ€” as REPLY, but for array values rather than strings. Arrays, but make it a reply ๐Ÿ’ฌ.
  • RPROMPT <S>
  • RPS1 <S> โ€” this prompt is displayed on the right-hand side of the screen when the primary prompt is being displayed on the left ๐ŸŒˆ. Heads up: this does not work if the SINGLE_LINE_ZLE option is set. It's expanded in the same way as PS1.
  • RPROMPT2 <S>
  • RPS2 <S> โ€” this prompt is displayed on the right-hand side of the screen when the secondary prompt is being displayed on the left ๐ŸŒธ. Also does not work if the SINGLE_LINE_ZLE option is set. It's expanded in the same way as PS2.
  • SAVEHIST โ€” the maximum number of history events to save in the history file ๐Ÿ“œ.

If this is made local, it is not implicitly set to 0, but may be explicitly set locally. Local girlies, read that twice.

  • SPROMPT <S> โ€” the prompt used for spelling correction ๐Ÿ”ค. The sequence %R expands to the string which presumably needs spelling correction, and %r expands to the proposed correction. All other prompt escapes are also allowed.

The actions available at the prompt are [nyae]:

  • n (no) (default) โ€” discard the correction and run the command.
  • y (yes) โ€” make the correction and run the command.
  • a (abort) โ€” discard the entire command line without running it.
  • e (edit) โ€” resume editing the command line.

Pick your path, bestie. Choose wisely ๐Ÿ’….

  • STTY โ€” if this parameter is set in a command's environment, the shell runs the stty command with the value of this parameter as arguments in order to set up the terminal before executing the command ๐Ÿ–ฅ๏ธ. The modes apply only to the command, and are reset when it finishes or is suspended. If the command is suspended and continued later with the fg or wait builtins it will see the modes specified by STTY, as if it were not suspended. This (intentionally) does not apply if the command is continued via kill -CONT. STTY is ignored if the command is run in the background, or if it is in the environment of the shell but not explicitly assigned to in the input line. This avoids running stty at every external command by accidentally exporting it. Also note that STTY should not be used for window size specifications; those will not be local to the command.

If the parameter is set and empty, all of the above applies except that stty is not run. This can be useful as a way to freeze the tty around a single command, blocking its changes to tty settings, similar to the ttyctl builtin. Freeze frame, but for your terminal โ„๏ธ.

  • TERM <S> โ€” the type of terminal in use ๐Ÿ–ฑ๏ธ. This is used when looking up termcap sequences. An assignment to TERM causes zsh to re-initialize the terminal, even if the value does not change (e.g., TERM=$TERM). It is necessary to make such an assignment upon any change to the terminal definition database or terminal type in order for the new settings to take effect. Yes, the classic TERM=$TERM trick โ€” it's not a no-op, it's a refresh, iykyk.
  • TERMINFO <S> โ€” a reference to your terminfo database, used by the terminfo library when the system has it; see terminfo(5) ๐Ÿ“š. If set, this causes the shell to reinitialise the terminal, making the workaround TERM=$TERM unnecessary. Glow up ๐Ÿ™Œ.
  • TERMINFO_DIRS <S> โ€” a colon-separated list of terminfo databases, used by the terminfo library when the system has it; see terminfo(5) ๐Ÿ—‚๏ธ. This variable is only used by certain terminal libraries, in particular ncurses; see terminfo(5) to check support on your system. If set, this causes the shell to reinitialise the terminal, making the workaround TERM=$TERM unnecessary. Note that unlike other colon-separated arrays this is not tied to a zsh array โ€” it's out here living its own independent life, main character energy ๐Ÿ‘‘.
  • TIMEFMT โ€” the format of process time reports with the time keyword โณ. The default is %J %U user %S system %P cpu %*E total. Recognizes the following escape sequences, although not all may be available on all systems, and some that are available may not be useful:

  • %% โ€” literally just outputs a %. that's it, that's the whole vibe ๐ŸŽ€
  • %U โ€” CPU seconds spent in user mode โฑ๏ธ
  • %S โ€” CPU seconds spent in kernel mode ๐Ÿง 
  • %E โ€” elapsed time, in seconds โณ
  • %P โ€” the CPU percentage, computed as 100*(%U+%S)/%E ๐Ÿ“Š
  • %W โ€” how many times the process was swapped ๐Ÿ”„
  • %X โ€” the average amount in (shared) text space used, in kilobytes ๐Ÿ“š
  • %D โ€” the average amount in (unshared) data/stack space used, in kilobytes ๐Ÿ—‚๏ธ
  • %K โ€” the total space used (%X+%D), in kilobytes ๐Ÿ’พ
  • %M โ€” the max memory the process had in use at any one time, in kilobytes ๐Ÿ˜
  • %F โ€” the number of major page faults (page needed to be brought from disk) ๐Ÿ’ฝ
  • %R โ€” the number of minor page faults ๐Ÿ’ซ
  • %I โ€” the number of input operations ๐Ÿ“ฅ
  • %O โ€” the number of output operations ๐Ÿ“ค
  • %r โ€” the number of socket messages received ๐Ÿ“ก
  • %s โ€” the number of socket messages sent ๐Ÿ“ถ
  • %k โ€” the number of signals received ๐Ÿšจ
  • %w โ€” number of voluntary context switches (waits) ๐Ÿ”
  • %c โ€” number of involuntary context switches ๐Ÿ˜ตโ€๐Ÿ’ซ
  • %J โ€” the name of this job ๐Ÿ‘‘

okay and here's a cute little flex: you can slip a star in between the percent sign and the flags that print time (like %*E) and it makes the time print out in hh:mm:ss.ttt format โ€” hours and minutes only get printed if they're not zero, ngl that's so clean โœจ

or, if you're feeling metric, m or u can go there instead (like %mE) and you get your time output in milliseconds or microseconds respectively. pick your unit, bestie ๐Ÿซถ


TMOUT โ€” if this parameter is nonzero, the shell gets an ALRM signal if a command is not entered within however many seconds you specified after issuing a prompt โฐ if there's a trap on SIGALRM, it gets executed and a brand new alarm is scheduled using the value of the TMOUT parameter after the trap runs. but if no trap is set, and the idle time of the terminal is not less than the value of the TMOUT parameter, zsh terminates. otherwise a new alarm is scheduled to TMOUT seconds after the last keypress. so likeโ€ฆ set it, but know what you're doing ๐Ÿ’€

TMPPREFIX โ€” a pathname prefix the shell uses for all its temporary files ๐Ÿ—ƒ๏ธ note that this should include an initial part for the filename as well as any directory names. the default is /tmp/zsh.

TMPSUFFIX โ€” a filename suffix the shell uses for temporary files created by process substitutions (e.g. =(list)) ๐Ÿงš note that the value should include a leading dot . if you want it interpreted as a file extension. the default is to not append any suffix at all โ€” so, like, only assign this when you actually need it, then unset it again. we love a clean exit ๐Ÿ™ˆ

WORDCHARS <S> โ€” a list of non-alphanumeric characters that the line editor considers part of a word ๐Ÿ”ค

ZBEEP โ€” if set, this gives you a string of characters that gets output to the terminal instead of beeping. it can use all the same codes as the bindkey command, as described in the zsh/zle module entry in zshmodules(1) ๐ŸŽต this may have a visible instead of an audible effect โ€” for example, the string \e[?5h\e[?5l on a vt100 or xterm will have the effect of flashing reverse video on and off (and if you usually use reverse video, you should use the string \e[?5l\e[?5h instead, bestie, flip it) ๐Ÿ”ฆ this takes precedence over the NOBEEP option, no cap.

ZDOTDIR โ€” the directory to search for shell startup files (.zshrc, etc), if not $HOME ๐Ÿ 


๐ŸŒธ zle_bracketed_paste ๐ŸŒธ

so many terminal emulators have a feature that lets applications identify when text is pasted into the terminal rather than being typed normally. for ZLE, that means special characters like tabs and newlines can actually be inserted instead of invoking editor commands ๐ŸŽ‰ and like, furthermore, pasted text forms a single undo event, and if the region is active, pasted text will replace the region. iconic behaviour honestly ๐Ÿ‘‘

this two-element array contains the terminal escape sequences for enabling and disabling the feature ๐Ÿ”ง these escape sequences are used to enable bracketed paste when ZLE is active and disable it at other times. unsetting the parameter has the effect of ensuring that bracketed paste remains disabled. periodt.

๐ŸŒˆ zle_highlight ๐ŸŒˆ

an array describing contexts in which ZLE should highlight the input text ๐Ÿ–๏ธ see Character Highlighting in zshzle(1) for the full lore.

๐Ÿ’œ ZLE_LINE_ABORTED ๐Ÿ’œ

this parameter is set by the line editor when an error occurs ๐Ÿ˜ญ it contains the line that was being edited at the point of the error. print -zr -- $ZLE_LINE_ABORTED can be used to recover the line โ€” literally your safety net fr fr. only the most recent line of this kind is remembered, so don't get cocky ๐Ÿซ 

๐Ÿฆ‹ ZLE_REMOVE_SUFFIX_CHARS and ZLE_SPACE_SUFFIX_CHARS ๐Ÿฆ‹

these parameters are used by the line editor. in certain circumstances, suffixes (typically space or slash) added by the completion system will be removed automatically โ€” either because the next editing command wasn't an insertable character, or because the character was marked as requiring the suffix to be removed ๐Ÿงน

these variables can contain the sets of characters that will cause the suffix to be removed. if ZLE_REMOVE_SUFFIX_CHARS is set, those characters will cause the suffix to be removed; if ZLE_SPACE_SUFFIX_CHARS is set, those characters will cause the suffix to be removed and replaced by a space โœจ

if ZLE_REMOVE_SUFFIX_CHARS is not set, the default behaviour is equivalent to:

ZLE_REMOVE_SUFFIX_CHARS=$' \t\n;&|'

if ZLE_REMOVE_SUFFIX_CHARS is set but is empty, no characters have this behaviour. ZLE_SPACE_SUFFIX_CHARS takes precedence, so that the following:

ZLE_SPACE_SUFFIX_CHARS=$'&|'

causes the characters & and | to remove the suffix but to replace it with a space ๐Ÿซถ

to illustrate the difference โ€” suppose the option AUTO_REMOVE_SLASH is in effect and the directory DIR has just been completed, with an appended /, and following which the user types &:

  • the default result is DIR& ๐ŸŽ€
  • with ZLE_REMOVE_SUFFIX_CHARS set but without including &, the result is DIR/& ๐Ÿ˜ฌ
  • with ZLE_SPACE_SUFFIX_CHARS set to include &, the result is DIR & ๐Ÿ’…
heads up bestie: certain completions may provide their own suffix removal or replacement behaviour which overrides the values described here. see the completion system documentation in zshcompsys(1) ๐Ÿ“–

โญ ZLE_RPROMPT_INDENT <S> โญ

if set, this is used to give the indentation between the right hand side of the right prompt in the line editor โ€” as given by RPS1 or RPROMPT โ€” and the right hand side of the screen ๐Ÿ“ if not set, the value 1 is used.

typically you'd use this to set the value to 0 so the prompt appears flush with the right hand side of the screen. this is not the default because many terminals do not handle this correctly, in particular when the prompt appears at the extreme bottom right of the screen ๐Ÿ˜ต recent virtual terminals are more likely to handle this case correctly. some experimentation is necessary โ€” go forth and fiddle, you got this ๐Ÿงช


and that's a wrap on zshparam(1), bestie!! ๐ŸŽ€โœจ this was zsh 5.9.2, dated July 12, 2026 โ€” go forth, set your parameters responsibly, and slay ๐Ÿ’…๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from