Skip to content

Instantly share code, notes, and snippets.

@ClementNerma
Last active February 7, 2025 20:27
Show Gist options
  • Save ClementNerma/1dd94cb0f1884b9c20d1ba0037bdcde2 to your computer and use it in GitHub Desktop.
Save ClementNerma/1dd94cb0f1884b9c20d1ba0037bdcde2 to your computer and use it in GitHub Desktop.

ZSH CheatSheet

This is a cheat sheet for how to perform various actions to ZSH, which can be tricky to find on the web as the syntax is not intuitive and it is generally not very well-documented.

Strings

Description Syntax
Get the length of a string ${#VARNAME}
Get a single character ${VARNAME[index]}
Get the string from a specific index ${VARNAME[index,-1]}
Get a substring ${VARNAME[from,to]}
Replace the first occurrence in a string ${VARNAME/toreplace/replacement}
Replace all occurrences in a string ${VARNAME//toreplace/replacement}
Cut a string after a model ${VARNAME%%model*}
Check if a string starts by a specific substring if [[ $VARNAME = "startstr"* ]]
Check if a string contains a substring if [[ $VARNAME = *"substring"* ]]
Check if a string ends by a specific substring if [[ $VARNAME = *"substring" ]]

Arrays

Description Syntax
Create an array VARNAME=()
Create an array with initial values VARNAME=(value1 value2 value3)
Push to an array VARNAME+=(value)
Access an array's element VARNAME[index]
Remove first element from an array (shift) shift VARNAME
Remove last element from an array (pop) shift -p VARNAME
Get an array's length ${#VARNAME}
Iterate over an array's values for value in $VARNAME;
Get index of a value in an array (0 if not found) ${VARNAME[(Ie)value]}
Get index of a value in an array (${#VARNAME} + 1 if not found) ${VARNAME[(ie)value]}
Get an array slice after the specified index ${VARNAME:index}
Get an array slice after the specified index ${VARNAME:index:length}
Check if a value is contained in an array if (( $VARNAME[(Ie)value] ));
Check if an array is empty if [[ -z $VARNAME ]]
Check if an array is not empty if [[ ! -z $VARNAME ]]
Remove an element from an array VARNAME[index]=()

Associative arrays (= maps / dictionaries)

Associate arrays are the equivalent of hash maps or dictionaries in many other programming languages: unlike arrays, they can use string keys, and these don't necessary have an order.

Description Syntax
Create an associative array typeset -A VARNAME=()
Create an associative array with initial values typeset -A VARNAME=( [key1]=value1 [key2]=value2 )
Add a new key to the array VARNAME[key]=value
Access the array's elements $VARNAME[key]
Remove a key from the array unset 'VARNAME[key]'
Get the array's number of elements ${#VARNAME}
Iterate over the array's values for value in $VARNAME;
Iterate over the array's keys for key in ${(k)VARNAME};
Iterate over the array's key-value pairs for key value in ${(kv)VARNAME};

Arithmetics

Description Syntax
Compute a mathematical expression (variables don't need to be prefixed with $ in it) $((expression))

Variables

Description Syntax
Get the value of a variable whose name is in another variable ${(P)NAMEVAR}
Get the list of all defined variables, as an array ${(k)parameters}
Delete a variable unset VARNAME

Functions

Description Syntax
Declare a local variable (not accessible outside the function) local varname=...
Get the original executable name $0
Get a parameter $1 (second is $2, etc.)
Expand all parameters $*
Expand all parameters but keep them quoted if needed $@ (tip: it's an array!)
Get the number of parameters (so not counting $0) $#
Remove the first parameter from $@ shift
Remove the last parameter from $@ shift -p
Exit the function with a status code (behaves like for a command) return 1 (or any other code)
Get the list of all functions, as an array ${(k)functions}
Delete a function unset -f func_name

Aliases

Description Syntax
Display the list of all defined aliases alias
Get the list of all defined aliases, as an array ${(k)aliases}
Define an alias alias name="command arg1 arg2 arg3 ..."
Remove an alias unalias name
Get the arguments, with escaped spaces ${@:q}

Conditionals

A word on conditionals

Syntaxes:

# 1)
if expression
then
    # instructions
fi

# 2)
if expression; then
    # instructions
fi

# 3)
if expression; then ...; fi

# 4)
if expression; then
    # instructions
else
    # instructions
fi

# 5)
if expression; then
    # instructions
elif expression
    # instructions
else
    # instructions
fi
Description Syntax
Check if a string is empty or not defined if [[ -z $VARNAME ]];
Check if a string is defined and not empty if [[ -n $VARNAME ]];
Check if a file exists if [[ -f "filepath" ]];
Check if a directory exists if [[ -d "dirpath" ]];
Check if a symbolic link exists if [[ -L "symlinkpath" ]];
Check if a shell option is set if [[ -o OPTION_NAME ]];
Check if two values are equal if [[ $VAR1 = $VAR2 ]];
Check if two values are different if [[ $VAR1 != $VAR2 ]];
Check if a number is greater than another if (( $VAR1 > $VAR2 ));
Check if a number is smaller than another if (( $VAR1 < $VAR2 ));
Check if a command exits successfully (exit code 0) if command arg1 arg2 ...
Check if a command doesn't exit successfully (exit code != 0) if ! command arg1 arg2 ...

Note that the $ symbol preceding variables' names in arithmetic expression (((...))) are purely optional, so you can perfectly write if (( VAR1 < VAR2 )); for instance.

You can read all dash - options in ZSH's manual, as there are many different ones: http://zsh.sourceforge.net/Doc/Release/Conditional-Expressions.html

Loops

Syntaxes:

# 1)
for itervarname in iterable
do
    # instructions
done

# 2)
for itervarname in iterable; do
    # instructions
done

# 3)
for itervaname in iterable; do ...; done
Description Syntax
Iterate over a range (inclusive) for i in {from..to};
Iterate over a list of filesystem items for i in globpattern;
Iterate over a list of filesystem items, fail silently if no match found for i in globpattern(N);

Examples cheat sheet

Return a value from within a function:

function add() {
    local sum=$(($1 + $2))
    echo $sum
}

function add_twice() {
    local sum=$(add $1 $2) # get the callee's STDOUT
    local sum_twice=$(add $sum $sum)
    echo $sum_twice
}

echo $(add 2 3) # 5
echo $(add_twice 2 3) # 10

A word on conditionals

Conditionals use expressions, such as in if [[ -z $VARNAME ]]; the expression is [[ -z $VARNAME ]]. These can also be used in while loops, as well as be used outside of blocks:

[[ -z $VARNAME ]] && echo "VARNAME is not defined or empty!"
[[ -f $FILEPATH ]] && echo "File exists!"

This works because conditional expressions ([[ ... ]] and (( ... ))) don't actually return a value; they behave like commands and as such set the status code to 0 if the condition is true, or 1 else.

If we want to display the message only if the condition is falsey:

[[ -z $VARNAME ]] || echo "VARNAME is not empty!"
[[ -f $FILEPATH ]] || echo "File does not exist!"
@wdeshazer
Copy link

wdeshazer commented Jan 5, 2025

I have found that it is possible to put a parameter/variable for the width in the format modifier flag (l::), which makes dynamic width formatting possible, but I cannot find a similar capability for the inner or outer padding characters. Any suggestions?

var='Hello, World!'
print ${(l:$(( $(tput cols)/2 )):)var}
#                                     Hello, World!

@andelink
Copy link

andelink commented Jan 10, 2025

I have found that it is possible to put a parameter/variable for the width in the format modifier flag (l::), which makes dynamic width formatting possible, but I cannot find a similar capability for the inner or outer padding characters. Any suggestions?

@wdeshazer here are the docs:

  • l:expr::string1::string2: Pad the resulting words on the left. Each word will be truncated if required and placed in a field expr characters wide. The arguments :string1: and :string2: are optional; neither, the first, or both may be given. See the docs for their usage details.
  • r:expr::string1::string2: As l, but pad words on the right and insert string2 immediately to the right of the string to be padded. Left and right padding may be used together. In this case the strategy is to apply left padding to the first half width of each of the resulting words, and right padding to the second half. If the string to be padded has odd width the extra padding is applied on the left.

I have found the (R) and (I) useful for slicing associative arrays. This technique is gleaned from a variety of sources that I have to recover.

... and relevant docs for r/R and i/I: Zsh Manual Section 15.2.3 Array Parameters - Subscript Flags


The official zsh documentation is not too bad in my experience. Sometimes I find it to be a little scattered (within its own manual and user guide), or not detailed enough on some particular matters, but overall it covers a lot. I set up a quick search in my browser to easily filter through their docs with a search engine (i.e. site:zsh.sourceforge.io).

Also available in your terminal, of course (man pages)! They are spread out by concept area. A subset of them returned by man -k zsh:

zsh          Zsh overview (this section)
zshroadmap   Informal introduction to the manual
zshmisc      Anything not fitting into the other sections
zshexpn      Zsh command and parameter expansion
zshparam     Zsh parameters
zshoptions   Zsh options
zshbuiltins  Zsh built-in functions
zshzle       Zsh command line editing
zshcompwid   Zsh completion widgets
zshcompsys   Zsh completion system
zshcompctl   Zsh completion control
zshmodules   Zsh loadable modules
zshtcpsys    Zsh built-in TCP functions
zshzftpsys   Zsh built-in FTP client
zshcontrib   Additional zsh functions and utilities
zshall       Meta-man page containing all of the above

I've often found myself opening up zshall in a pager and then searching for the term of interest, otherwise I'd not know how to find it across the different sections they have.

Another good one is zsh-lovers, community maintained. You'll have to install that one on your own. I think I installed it via homebrew a while back.

@wdeshazer
Copy link

wdeshazer commented Jan 23, 2025

@andelink, the man references are great (and I use them extensively), but my question is about dynamic specification of the values. I would love to do:

# Note this does not work for anyone who might get confused
print ${(l:$w::$char1::$char2:)param} [edited per @ferdnyc]

but only the width can be specified dynamically. Using your extraction from the docs, Only the width allows for an "expression" and the other two must be "strings". Those strings can't be passed as a parameter? The answer is no and I think your doc reference supports that, but then what is the recommended zsh alternative for dynamic formatting. (Use perl? 💀)

@ferdnyc
Copy link

ferdnyc commented Jan 23, 2025

@wdeshazer You left out some :s, but you can do this:

eval "print \${(l:$w::$char1::$char2:)param}"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment