Z Shell#
Table of Contents#
zsh --version
Output: zsh 5.9 (x86_64-apple-darwin23.0)
echo $ZSH_VERSION
Output: 5.9
man zsh
man zshexpn
man zshmisc # conditional expressions
man zshmodules
zsh --help # display options
Startup config files#
~/.zshrc
“runtime configuration”
Startup files
/etc/zlogin # run for login shells
~/.zlogin # run for login shells
/etc/zprofile # run for login shells
~/.zprofile # run for login shells
/etc/zshenv # run for every shell
~/.zshenv # run for every shell (usually)
/etc/zshrc # run for interactive shells
~/.zshrc # run for interactive shells
Shutdown files
/etc/zlogout # run for login shells
~/.zlogout # run for login shells
zsh -f # start a new interactive shell and set the `NO_RCS` option so that no zsh startup files are run other than `/etc/zshenv`
Jobs#
https://zsh.sourceforge.io/Doc/Release/Jobs-_0026-Signals.html
Jobs
&
operator - send a task to the backgroundjobs
- list tasks that are currently running in the backgroundfg n
- bring taskn
back to the foreground from the background (bash)%n
orfg %n
- bring taskn
back to the foreground from the background (zsh)fg
impliesfg %1
%
orfg %
%-
orfg %-
bring the previous task to the foreground from the background (zsh)%+
or%%
orfg %+
orfg %%
bring the current task to the foreground from the background (zsh)Ctrl-Z - suspend a process that is currently running in the foreground and then send it back to the background
bg
- continue running all suspended background processesbg n
- continue running suspended background processesn
(bash)bg %n
- continue running suspended background processesn
(zsh)bg %
?bg %-
?bg %+
?
ping 192.168.10.56 > ping.log & # send stdout to the background (stderr prints to the screen)
ping 192.168.10.56 &> ping.log & # send both stdout and stderr to the background
ping google.com > /dev/null &
ping amazon.com > /dev/null &
ping oreilly.com > /dev/null &
jobs -p
[1] running ping google.com > /dev/null
[2] - running ping amazon.com > /dev/null
[3] + running ping oreilly.com > /dev/null
%3
[3] - 4048 running ping oreilly.com > /dev/null
Ctrl-Z
[3] + 4048 suspended ping oreilly.com > /dev/null
jobs -p
[1] running ping google.com > /dev/null
[2] - running ping amazon.com > /dev/null
[3] + suspended ping oreilly.com > /dev/null
%2
[2] - 4037 running ping amazon.com > /dev/null
Ctrl-Z
[2] + 4037 suspended ping amazon.com > /dev/null
jobs -p
[1] running ping google.com > /dev/null
[2] + suspended ping amazon.com > /dev/null
[3] - suspended ping oreilly.com > /dev/null
bg %3
[3] - 4048 continued ping oreilly.com > /dev/null
jobs -p
[1] running ping google.com > /dev/null
[2] + suspended ping amazon.com > /dev/null
[3] - running ping oreilly.com > /dev/null
Parameters (Variables)#
Normal parameters are also called scalars because they have just one word in them.
# there are no spaces around parameter assignment
foo=bar # stores the value `bar` in the parameter `foo`
foo='This is a parameter.' # stores the value `'This is a parameter.'` in the parameter `foo`
foo ='This is a parameter.' # attempts to invoke the non-existent command `foo` with argument `='This is a parameter.'`
foo= 'This is a parameter.' # stores the empty string in the parameter `foo`
Parameter Expansion (or Substitution)
foo=bar
print $foo # bar
print '$foo is "'$foo'"' # $foo is "This is a parameter."
Modifiers
pattern matching
partial replacement of modified parts of the original string
Arrays#
Arrays are a special kind of parameter that have more than one word in them.
arr=(one two three four) # original command
print $arr # one two three four
print ${arr} # one two three four
print ${arr[2]} # two
print ${arr[2,-1]} # two three four
print ${arr[2,-1][1]} # two
print ${arr[2,-1][1][2,-1]} # wo
print $#arr # 4
print $arr # one two three four
# sets the second element to the empty string but does not remove the second element
arr[2]=
print $#arr # 4
print $arr # one three four
# replaces the second element with an array of length zero, which removes it
arr[2]=()
print $#arr # 3
print $arr # one three four
arr=(what kind of fool am i) # original command
arr[2]=species
print $arr # what species of fool am i
arr[2]=(a piece)
print $arr # what a piece of fool am i
arr[-3,-1]=(work is a man)
print $arr # what a piece of work is a man
“You need typeset
or equivalent if you want to the array to be local to a function. The neat way is typeset -a
, which creates an empty array, but as long as you assign to the array before trying to use it any old typeset will do.”
Subscripts have flags for special purposes.
r
“reverse subscripting”: search through arrays and match and return values or the empty string (starting from the left)R
“reverse subscripting”: search through arrays and match and return values or the empty string (starting from the right)i
return the index matched (starting from the left)I
return the index matched (starting from the right)
arr=(se vuol ballare signor contino)
print ${arr[(r)s*]} # se
print ${arr[(R)s*]} # signor
arr=(some words); args () { print $#; }
args ${arr[(r)s*]} # 1
# the unquoted empty string is dropped
args ${arr[(r)X*]} # 0
# the quoted empty string is passed as a single empty argument
args "${arr[(r)X*]}" # 1
arr=(se vuol venire nella mia scuola)
print ${arr[(i)v*]} # 2
print ${arr[(I)v*]} # 3
--
in a command line says that there are no more options that begin with a -
print -hello # print: bad option: -h
print -- -hello # -hello
print - -hello # -hello (non-standard)
“The shell is “eight-bit clean” which means that you can have any of he 256 possible characters anywhere in your string. For example, $’foo\000bar’ has an embedded ASCII NUL in it (that’s not a misprint–officially, ASCII non-printing characters have two- or three-letter abbreviations). Usually this terminates a string, but the shell works around this when you are using it internally; when you try and pass it as an argument to an external programme, however, all bets are off. Almost certainly the first NUL in that case will cause the programme to think the string is finished, because no information about the length of arguments is passed down and there’s nothing the shell can do about it. Below, the shell’s echo knows about the shell’s 8-bit conventions, and prints out the NUL, which the terminal doesn’t show, then the remainder of the string. The external version of echo didn’t know any better than to stop when it reached the NUL.”
echo $'foo\000bar'
Output: foobar
/bin/echo $'foo\000bar'
Output: foo
echo
is a shell builtin.
type echo
Output: echo is a shell builtin
/bin/echo
is an external program.
type /bin/echo
Output: /bin/echo is /bin/echo
Sequences and Brace Expansion#
echo {0..10}
echo {00..10}
(Bash v4+)echo {10..0}
echo {10..0..2}
(Bash v4+)echo {a..z}
vsecho {A..z}
vsecho {a..z} {A..Z}
vsecho {a..z}{A..Z}
echo {z..a..2}
(Bash v4+)
Quoting#
“Using quotes is an important part of controlling the effects of the shell’s various substitutions.
Backslashes are trivial: you can quote any character whatsoever from the shell with a backslash even if it didn’t mean anything unquoted. You can take any old string at all, whatever it has in it–random collections of quotes, backslashes, unprintable characters–quote every single character with a backslash, and the shell will treat it as a plain string”
print \h\e\l\l\o\ \w\o\r\l\d\!\ \\\n
Output: hello world!\n
read string
Enter the following: This is a *string* with various `special' characters
echo $string
Output: This is a *string* with various `special' characters
print -r -- ${(q)string}
Output: This\ is\ a\ \*string\*\ with\ various\ \`special\'\ characters
print -r -- ${(qq)string}
Output: 'This is a *string* with various `special'\'' characters'
print -r -- ${(qqq)string}
Output: "This is a *string* with various \`special' characters"
print -r -- ${(qqqq)string}
Output: $'This is a *string* with various `special\' characters'
eval print -r -- ${(q)string}
Output: This is a *string* with various `special' characters
echo "print 'a quoted string' and\ another\ argument" > file
read -r line < file
for word in ${(z)line}; do
print -r "quoted: $word"
print -r "unquoted: ${(Q)word}"
done
Output:
quoted: print
unquoted: print
quoted: 'a quoted string'
unquoted: a quoted string
quoted: and\ another\ argument
unquoted: and another argument
Option RC_QUOTES converts two single quotes into one single quote inside single quotes.
unsetopt rcquotes
print -r 'A ''quoted'' string'
Output: A quoted string
setopt rcquotes
print -r 'A ''quoted'' string'
Output: A 'quoted' string
POSIX quotes begin with $'
and end with '
.
cat <<<$'Line\tone\nLine\ttwo'
is equivalent to
print 'Line\tone\nLine\ttwo'
Output:
Line one
Line two
Without the initial $
:
cat <<<'Line\tone\nLine\ttwo'
Output: Line\tone\nLine\ttwo
Double quotes
parameter expansion
command substitution
arithmetic subsitition
NO process substitution
NO brace, initial tilde, equal sign expansion
NO patterns
“Word splitting is usually suppressed except in the case of parameter substitution which allows you to specify that normal word-splitting will occur as well as other forms of substitution using the flag (@)
.”
arr=(one two)
print $(echo foo bar) $arr
Output: foo bar one two
print -l $(echo foo bar) $arr
Output:
foo
bar
one
two
print -l "$(echo foo bar) $arr"
Output: foo bar one two
print -l "${arr[@]}" "${(@)arr}"
Output:
one
two
one
two
args () { print $#; } # report the number of arguments
echo "Words on line one\nWords on line two\n" > file
cat file
Output:
Words on line one
Words on line two
args $(<file)
Output: 8
args "$(<file)"
Output: 1
args "${(f)$(<file)}"
Output: 2
Flags
@
f
split the result of the expansion one word per linej:,:
replace with commaq
quote with backslashesqq
quote with single quotesqqq
quote with double quotesqqqq
quote with POSIX quotesQ
unquotez
split a line into an array
History Expansion#
View the command-line history list.
history
View the n
most recent command lines in the command-line history list.
history -n
View the history characters.
echo $HISTCHARS
!^#
View the history list’s capacity.
echo $HISTSIZE
50000
echo $SAVEHIST
10000
echo $HISTFILE
~/.zsh_history
History Characters
!
history character^
modification character#
comment character
A history expansion begins with the first character of the histchars parameter !
. The first character is followed by an optional event designator and then an optional word designator; if neither of these designators is present then no history expansion occurs.
! <event designator> : <word designator> : <modifier>
An event designator is a reference to a command-line entry in the history list. !
is the event designator for the previous command. A word designator indicates which word or words of a given command line are to be included in a history reference. The event designator and the word designator are separated by a colon :
but may be omitted if the word designator begins with ^
, $
, *
, -
, %
.
does work
echo 'hello!!'
echo "hello\!\!"
does not work
echo hello!!
echo "hello!!"
Event Designators
!!
refer to the previous command!#
refer to the current command-line typed so far!n
refer to command-linen
!-n
refer to the current command-line minusn
!str
refer to the most recent command starting withstr
!?str[?]
refer to the most recent command containingstr
; the trailing?
is necessary if this reference is to be followed by a modifier!{...}
insulate a history reference from adjacent characters
echo one two three # previous command
!! # echo one two three
echo !! # echo echo one two three
echo !# # echo echo
!-1 # echo one two three
!echo # echo one two three
Word Designators
0
the first input word (i.e., the command)n
then
th argument^
the first argument$
the last argumentx-y
a range of words (x
defaults to 0)*
all the arguments; or a null value if there are nonex*
abbreviates the rangex-$
x-
likex*
without the final word$
echo one two three # original command
!!0 # echo
!!^ # one
!!1 # one
!!1* # one two three
!!1- # one two
!!2-3 # two three
!!$ # three
echo !?tr?:* # echo tree . -aL 3
Modifiers#
Modifiers are used in
history expansion
parameter substitution
file name generation (globbing)
Modifiers
a
transform a file name into an absolute pathA
transform a file name into an absolute path and resolve symlinkshn
keep the head of the path (i.e., everything except the last component of the path); usen
to keep the firstn
components of the path (the root directory/
is the first component of an absolute path)tn
keep the tail of the path (i.e., the last component of the path); usen
to keep the lastn
components of the pathr
remove the file name extensionl
convert everything to lowercaseu
convert everything to uppercase
Substitution Modifiers
s/<string>/<replacement>/<flag>
substitute<string>
with<replacement>
using an optional<flag>
global subsitution
gs/<string>/<replacement>/
s/<string>/<replacement>/:g
the metacharacter
&
expands to<string>
; to use the literal character&
escape the metacharacter\&
ls script.sh # original command
!!^:a # /home/user/workspace/project/script.sh
ls /home/user/workspace/project/script.sh # original command
!!^:h # /home/user/workspace/project
!!^:h1 # /
!!^:h2 # /home
!!^:t # script.sh
!!^:t1 # script.sh
!!^:t2 # project/script.sh
!!^:t:r # script
!!^:t:r:u # SCRIPT
echo hello hello bonjour # original command
!!:s/hello/bonjour # echo bonjour hello bonjour
!!:gs/hello/bonjour # echo bonjour bonjour bonjour
param=~/file
print $param # /Users/<user>/file
print !-1:t # file
print ${param:t} # file
print foo # foo (enter)
^foo^bar # print bar (enter) (ctrl-c)
param='this sentence contains a foo.' #
print ${param:&} # print this\ sentence\ contains\ a\ bar. (tab)
print a sentence with a /real/live/bogus/path in it.
print !!:t # path in it.
arr=('a bar of chocolate' 'a bar of barflies' 'a barrier of barns')
print ${arr:s/bar/car} # a car of chocolate a car of barflies a carrier of barns
print ${arr:gs/bar/car} # a car of chocolate a car of carflies a carrier of carns
Modifiers in file name generation (i.e., globbing)
touch {parser,lexer,input,output}.c
print *.c # parser.c lexer.c input.c output.c
print *.c(:r) # parser lexer input output
mkdir -p stuff/subdir && touch stuff/{one,two}file.c
print stuff/* # stuff/onefile.c stuff/twofile.c stuff/subdir
print stuff/*(.) # stuff/onefile.c stuff/twofile.c
print stuff/*(.:r:t) # onefile twofile
Globbing (File Name Generation)#
Globbing Qualifiers
.
regular files (no directories nor special files)
File name modification is the only form of globing where the result is no longer a file name and is always performed at the end after all normal file name generation.
Arrays#
Indexed Arrays#
arr=(a b c)
print ${(t)arr} # "array"
Associative Arrays#
declare -A aarr # declare an associative array
typeset -A aarr # declare an associative array
print ${(t)aarr} # "association"
aarr[a]=1
aarr[b]=2
aarr[c]=3
aarr=([c]=3 [d]=4 [e]=5) # overwrite pre-existing associative array
aarr+=([c]=3 [d]=4 [e]=5) # modify pre-existing associative array
aarr=() # clear pre-existing associative array
print $aarr # "1 2 3 4 5"
print ${(v)aarr} # "1 2 3 4 5"
print ${(k)aarr} # "a b c d e"
print ${(kv)aarr} # "a 1 b 2 c 3 d 4 e 5"
print $aarr[a] # "1"
for k v in ${(kv)aarr}; do
print "$k -> $v"
done
# "a -> 1"
# "b -> 2"
# "c -> 3"
# "d -> 4"
# "e -> 5"
Login vs Non-login Shell#
Include the following function in file $HOME/.zshrc
.
# determine whether a shell is a login shell or a non-login shell
sl () {
if [[ -o login ]]; then
print yes
else
print no
fi
}
Log into the machine and check the shell type.
echo $0
-zsh
sl
yes
Start a new interactive non-login shell.
zsh
echo $0
zsh
sl
no
Start a new interactive login shell.
zsh -l
echo $0
zsh
sl
yes
Invoke a non-interactive shell on a file.
zsh filename
Environment Variables#
CPUTYPE
HISTCHARS
HISTFILE
HISTSIZE
EDITOR
LESSCLOSE
LESSOPEN
MAIL
MAIL_WARNING
MAILCHECK
MANPATH
PAGER
PROMPT
PS1
PS2
PS3
PS4
SAVEHIST
SHELL
USER
VISUAL
ZDOTDIR
CPUTYPE
echo $CPUTYPE
Output: arm64
PAGER
echo $PAGER
Output: less
SHELL
echo $SHELL
Output: /bin/zsh
which zsh
Output: /bin/zsh
echo $0
Output: -zsh
ZDOTDIR
If the user’s zsh startup files are located in the standard location–the user’s home folder–then the following command doesn’t display anything.
print $ZDOTDIR
Shell Options#
Each option describes one particular shell behavior. Options can be written uppercase or lowercase with as many or as few underscores as you like. An option with “no” in front just means the opposite of the option without (NOMATCH
and NOTIFY
have “no” as a part of their base name).
(NO_)APPEND_HISTORY
(NO_)AUTO_CD
(NO_)BAD_PATTERN
(NO_)BANG_HIST
(NO_)BARE_GLOB_QUAL
turn off zsh globbing behavior: file name modifiers(NO_)BEEP
(NO_)BG_NICE
(NO_)BSD_ECHO
(NO_)CD_ABLE_VARS
(NO_)CORRECT
(NO_)CORRECT_ALL
(NO_)CSH_JUNKIE_HISTORY
(NO_)CSH_JUNKIE_LOOPS
(NO_)CSH_JUNKIE_QUOTES
(NO_)CSH_NULL_GLOB
(NO_)EXTENDED_GLOB
(NO_)EXTENDED_HISTORY
(NO_)FUNCTION_ARG_ZERO
(NO_)GLOB_SUBST
(NO_)HIST_ALLOW_CLOBBER
(NO_)HIST_BEEP
(NO_)HIST_EXPIRE_DUPS_FIRST
(NO_)HIST_FIND_NO_DUPS
(NO_)HIST_IGNORE_ALL_DUPS
(NO_)HIST_IGNORE_DUPS
(NO_)HIST_IGNORE_SPACE
(NO_)HIST_NO_FUNCTIONS
(NO_)HIST_NO_STORE
(NO_)HIST_REDUCE_BLANKS
(NO_)HIST_SAVE_NO_DUPS
(NO_)HIST_VERIFY
if set, then after the substitution the line appears again with the changes instead of being immediately printed and executed(NO_)HUP
“hang up”(NO_)IGNORE_BRACES
(NO_)INC_APPEND_HISTORY
(NO_)INTERACTIVE_COMMENTS
(NO_)KSH_ARRAYS
make arrays behave more like Korn Shell arrays (braces are necessary; arrays are zero-indexed)(NO_)KSH_AUTOLOAD
(NO_)KSH_GLOB
turn on ksh globbing behavior(NO_)KSH_OPTION_PRINT
(NO_)LOCAL_OPTIONS
(NO_)LOCAL_TRAPS
(NO_)MONITOR
(NO_)MULTIOS
(NO_)NOMATCH
(NO_)NOTIFY
(NO_)POSIX_BUILTINS
(NO_)PROMPT_BANG
(NO_)PROMPT_PERCENT
(NO_)PROMPT_SUBST
(NO_)RCS
(NO_)RM_STAR_SILENT
(NO_)SH_FILE_EXPANSION
(NO_)SH_GLOB
turn off zsh globbing behavior(NO_)SH_OPTION_LETTERS
(NO_)SH_WORD_SPLIT
treat parameter assignment like bash(NO_)SHARE_HISTORY
(NO_)SINGLE_LINE_ZLE
(NO_)ZLE
set -o | sort # view a full list of set and unset options
set +o | sort # view a full list of set and unset options
setopt # view set options
unsetopt # view unset options
set # view positional parameters, zsh's way of passing arguments to scripts and functions
Resources#
[ h ] Z Shell
[ h ] An Introduction to the Z Shell.
[ h ] Falstad, Paul. (2022). The Z Shell Manual.
[ h ] Stephenson, Peter. (2003). A User’s Guide to the Z-Shell.
[ h ][ d ][ g ][ w ] Oh My Zsh
[ g ] Plugins
[ g ] 1password
[ g ] brew
[ g ] dotenv
[ g ] gh
[ g ] git
[ g ] git-lfs
[ g ] gitignore
[ g ] history
[ g ] jsontools
[ g ] macos
[ g ] nmap
[ g ] pip
[ g ] pipenv
[ g ] python
[ g ] sbt
[ g ] scala
[ g ] ssh-agent
[ g ] sudo
[ g ] vagrant
[ g ] vscode
[ g ] web-search
[ g ] z
[ g ] zsh-syntax-highlighting
more
other
[ y ]
05-16-2021
. DevDungeon. “Customizing Zsh”.[ y ]
07-13-2019
. Karl Hadwen. “Learn Zsh in 80 Minutes macOS - Oh My Zsh - Command Line Power User | @karlhadwen”.