You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 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"* ]]
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
${VARNAME[(i)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[(i)value]} <= ${#VARNAME} ));
Check if an array is empty
if [[ -z $VARNAME ]]
Check if an array is not empty
if [[ ! -z $VARNAME ]]
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)
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:
functionadd() {
local sum=$(($1+$2))echo$sum
}
functionadd_twice() {
local sum=$(add $1$2)# get the callee's STDOUTlocal sum_twice=$(add $sum$sum)echo$sum_twice
}
echo$(add 2 3)# 5echo$(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 exists!"
The note Get index of a value in an array (0 if not found) is incorrect; ${VARNAME[(ie)value]} does not return 0 if the item is not found. It instead returns one more than the length of the array.
The note Get index of a value in an array (0 if not found) is incorrect; ${VARNAME[(ie)value]} does not return 0 if the item is not found. It instead returns one more than the length of the array.
Indeed, it's with (Ie) that the index is 0. I fixed that in the document, thanks :) !
ps for this one, i had to download the postscript file, then run psnup -1 -Pa4 -pletter < refcard.ps > refcard-letter.ps, then manually rotate each page
They aren't identical if the pattern can match in more than one place:
% file=archive.tar.gz
% echo ${file%%.*}
archive
% echo ${file%.*}
archive.tar
That goes for `#` as well. The double-symbol version removes the longest
match, while the single symbol removes the shortest match.
Huh, I'm surprised the expansion modifiers aren't covered above, or in @akharrou 's otherwise rather snazzy cheatsheet find. Maybe they get overlooked because they're documented in the History Expansion section of zshexpn(1), but there is a note that (most) also work for filename generation and parameter expansion.
The one I use all the time is :r, to remove the last suffix from a filename. (${var:r} is basically a handy shorthand for ${var%.*}.) Great for writing loops to convert files between formats:
"${var:r}.${var:e}" almost == "${var}", unless the last part of ${var} contains no .. (Then it would mistakenly add one.)
${var:l} ${var:u}
Lowercase or uppercase the variable's value
Same as ${(L)var} and ${(U)var} but easier to type.
${var:P}
Make a path canonical and absolute
${fname:P} == $(realpath $fname)
${var:hN}
Go up N levels in the path hierarchy
Like wrapping N nested $(dirname $(dirname etc...) ) calls around the var.
${var:tN}
Leave N levels of hierarchy at the end of a path
Tail-end complement to ${var:hN}. With N == 0 or 1 (or omitted), it's just $(basename $var). With N > 1, an operation that's difficult to express with similar tools. Call it "tailname". var="a/path/of/any/depth/to/a/file"; echo "${var:t3}" => to/a/file
I actually got my explanation of ${var:hN} wrong, above. The same way ${var:tN} walks back from the filename part of the path, the :hN form walks down from the start of the path. So it's nothing like dirname at all.
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. However, I have yet to see any docs present the features quite as follows.
typeset -A aa=( [left]=right [up]=down [forward]=background [green]=brown )
# List matching values from hash
print ${aa[(R)back*|*own]}# background down brown# List keys for matching values from hash
print ${(k)aa[(R)back*|*own]}# forward up green# Return key-values from matching keys and assign to new hash subtypeset -A sub=(${(kv)aa[(R)back*|*own]})
printf"%10s => %s\n"${(kv)sub}# forward => background# up => down# green => brown# Print key-values for matching keys in hash
print ${(kv)aa[(I)up|left]}
In trying to find my original inspiration for this technique, I do see a nod in the Zsh Native Scripting Handbook. I believe this illustration is more demonstrative of the capabilities. When I find my original inspiration I will update my comment with a reference.
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?
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?
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.
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.
@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? 💀)
The note
Get index of a value in an array (0 if not found)is incorrect;${VARNAME[(ie)value]}does not return 0 if the item is not found. It instead returns one more than the length of the array.