Zsh: the sheet
Be aware it's not an exhaustive list.
Permalink to heading Basics Basics
Let’s start with some basic concepts.
Permalink to heading Zsh is probably Bash++ Zsh is probably Bash++
Zsh has many of the essential features of bash, ksh, or tcsh, so common syntaxes such as conditional statements, expansions, or assignments will work pretty much the same.
Zsh brings cool additional features you might find helpful, though.
Zsh stands for “Z-Shell” and is meant for Unix systems. It’s an interactive shell that wraps commands you use on the terminal.
Permalink to heading But Zsh is neither bash nor sh But Zsh is neither bash nor sh
Even if Zsh is highly compatible with Bash and sh, we’ll see there are some notable differences. As a result, the following might work:
zsh myscript
sh myscript.zsh
./myscript.sh
But it’s a bit misleading and you can even get unexpected errors in the worst-case scenario because the default behavior is not the same.
Permalink to heading Installing Zsh Installing Zsh
If Zsh is already available on your system, you can check if zsh is your current shell with:
echo $0
- If it says “zsh”, you are ready to go
- If it’s another shell, you can simply type
zsh
to switch prompt quickly - If you want to set Zsh as the default shell, type
chsh -s /bin/zsh
If Zsh is not yet on your system, it’s pretty straightforward to install.
Permalink to heading Best framework Best framework
You can install Oh my zsh, a wonderful framework that eases configuration and provides tons of customizations (e.g., themes, plugins, aliases, etc).
Permalink to heading The agnostic way The agnostic way
You can run the following in the terminal:
sudo apt update && apt install zsh && chsh -s /bin/zsh
The above command install the package and set it as the default shell. If you get an error with /bin/zsh
, you can use $(which zsh)
alternatively to locate Zsh on the system.
Depending on your Linux distribution, you have to replace sudo apt
with the appropriate command. For example, your will use yum -y install
for CentOS and pacman -S zsh
in Arch Linux.
Permalink to heading Configuration files Configuration files
Zsh uses configuration files (like Bash):
.zshenv # env vars
.zprofile # external commands
.zshrc # global settings and customizations such as autocompletion, case sensitivity, aliases, etc
.zlogin # commands on shell login
.zlogout # commands on shell exit
Permalink to heading The Shebang The Shebang
It’s the #!
at the top of bash files. “Bang” is for the exclamation point “!”:
#!/usr/bin/zsh
It’s essential not to forget it, as if you use #!/usr/bin/bash
, then the bash interpreter will be used when running ./myscript
, regardless of the default shell.
Permalink to heading Executing scripts Executing scripts
zsh myscript.zsh
Alternatively, you can make your script executable and run it:
chmod +x myscript.zsh && ./myscript.zsh
Permalink to heading Zsh can autocorrect Zsh can autocorrect
Zsh is smart enough to detect small typos and suggest corrections for commands:
zsh: correct ‘MISPELLED_COMMAND’ to ‘COMMAND’ [nyae]?
Note that it also works for folder names and files.
It’s pretty cool but you might get annoyed in some cases. You can disable autocorrection like that:
nocorrect MY_CUSTOM_COMMAND
Permalink to heading You don’t have to use cd
You don’t have to use cd
You might already know this trick, but in case you don’t, the change directory command is not necessary to browse directories with Zsh. The following command will get you to the desired path:
/Users/ella/Desktop/
It’s pretty convenient to quicky move to a nested directory, for example, by drag and droping the folder inside the terminal and pressing enter.
It’s possible thanks to the autocd
option.
Permalink to heading You can use keyboard shortcuts in the terminal You can use keyboard shortcuts in the terminal
Like in Bash, you can use shortcuts in the terminal to gain time and energy. For example, Ctrl + U
can delete from the cursor to the start of the line, and Ctrl + L
will clear the terminal.
Permalink to heading Best documentations Best documentations
- Read The Fabulous Manual:
man zsh
- Another Doc
- zsh.org
- zsh lovers
- Oh my zsh wiki
- iterm2
- zsh Arch Linux
Permalink to heading Scripting Scripting
You can use most tricks you learned in Bash and the syntax is the same. There are additional features and important differences, though.
Permalink to heading zsh arrays are 1-indexed zsh arrays are 1-indexed
It’s a major difference with Bash. Arrays do not start at 0
but 1
, which might be way less confusing and thus, more intuitive for most users:
MyArray=(All In One)
echo ${#MyArray[2]} # displays 2 in zsh (number of chars of the second element) and 3 in bash (number of chars of the third element)
As a result, the total length is the same as the last index in Zsh.
N.B.: Note that you can modify that default behavior to have 0-indexed arrays, but it’s not something I would recommend as a general rule.
Permalink to heading Zsh is better at globbing Zsh is better at globbing
In Bash, you will likely interact with the filesystem using the find
command. For example, to apply a command on all files, you might use:
find . -type f -print | xargs CUSTOM_COMMAND
In Zsh, you can use globbing:
CUSTOM_COMMAND **/*(.)
**/
is for recursion and the third wildcard *
is to target all elements. (.)
will match files.
Permalink to heading All glob qualifiers All glob qualifiers
You can combine many Glob qualifiers like filters to only target the elements you need.
Qualifier | Description |
---|---|
/ | directory |
F | non-empty directory (empty: (/^F) ) |
. | plain file |
@ | symbolic link |
* | executable plain file |
r /A /R | readable by owner/group/world |
w /I /W | writable by owner/group/world |
x /E /X | executable by owner/group/world |
s /S /t | setuid/setgid/sticky bit |
f spec | has chmod style permissions spec |
u: name : | owned by user name |
g: name : | owned by group name |
a[Mwhms][-+] n | access time in given units (see below) |
m[Mwhms][-+] n | modification time in given units |
L[kmp][-+] n | size in given units (see below) |
^ | negate following qualifiers |
- | toggle following links (first one turns on) |
N | whole pattern expands to empty if no match |
D | leading dots may be matched |
n | sort numbers numerically |
o[nLamd] | order by given code (see below; may repeat) |
O[nLamd] | order by reverse of given code |
[ num ] | select num -th file in current order |
[ num1 , num2 ] | select num1 -th to num2 -th file |
Permalink to heading Common tricks Common tricks
Be careful with qualifiers, as they are not magic. If you scan too large folders, you might get errors. Anyway, it eases common operations for sure.
Permalink to heading List files only List files only
ls **/*(.)
Permalink to heading List directories only List directories only
ls **/*(/)
Permalink to heading Find all files with specific extensions Find all files with specific extensions
ls **/*.md
Permalink to heading Find files larger than 25 megabytes Find files larger than 25 megabytes
ls **/*(.Lm+25)
Permalink to heading List files that have been modified during the last two days List files that have been modified during the last two days
ls **/*(.md-2)
Permalink to heading Change permissions for files owned by a specific user Change permissions for files owned by a specific user
chmod 644 **/*(u:ella:) # provided that ella exists ^^
Permalink to heading Oh my zsh alternatives? Oh my zsh alternatives?
Dev often recommend using Oh my zsh because it’s actively maintained and significantly more friendly to use and configure. It does not mean it’s the only way to customize zsh at all.
You could, for example, open the .zshrc
file and write specific lines to customize the prompt without any additional layer. The main caveat is it would be a bit more complicated, perhaps tedious, but many dev would likely stick with the native tools instead of installing frameworks:
# for all options @see https://zsh.sourceforge.io/Doc/Release/Prompt-Expansion.html
PROMPT='%F{red}%1~%f %# '
# aliases
alias gs='git status'
alias gc='git commit'
I totally respect that approach. I’m not a big fan of alternative frameworks, though. Most tools I’ve tested are not reliable, to me, or lack documentation and concrete examples.
Too much dependencies can be a concern. Besides, you often end up installing and loading tons of plugins while using only a small percentage of all features and aliases.
Permalink to heading Going further Going further
You might need more customizations and bindings.
Permalink to heading Get some inspiration in Kali Linux Get some inspiration in Kali Linux
It’s worth diving into Kali Linux and its default .zshrc
file. The pen-testing distribution makes interesting use of advanced features such as bindings and completions:
# ~/.zshrc file for zsh interactive shells.
# see /usr/share/doc/zsh/examples/zshrc for examples
setopt autocd # change directory just by typing its name
#setopt correct # auto correct mistakes
setopt interactivecomments # allow comments in interactive mode
setopt magicequalsubst # enable filename expansion for arguments of the form βanything=expressionβ
setopt nonomatch # hide error message if there is no match for the pattern
setopt notify # report the status of background jobs immediately
setopt numericglobsort # sort filenames numerically when it makes sense
setopt promptsubst # enable command substitution in prompt
# enable completion features
autoload -Uz compinit
compinit -d ~/.cache/zcompdump
zstyle ':completion:*:*:*:*:*' menu select
zstyle ':completion:*' auto-description 'specify: %d'
zstyle ':completion:*' completer _expand _complete
zstyle ':completion:*' format 'Completing %d'
zstyle ':completion:*' group-name ''
zstyle ':completion:*' list-colors ''
zstyle ':completion:*' list-prompt %SAt %p: Hit TAB for more, or the character to insert%s
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'
zstyle ':completion:*' rehash true
zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s
zstyle ':completion:*' use-compctl false
zstyle ':completion:*' verbose true
zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd'
# force zsh to show the complete history
alias history="history 0"
# configure `time` format
TIMEFMT=$'\nreal\t%E\nuser\t%U\nsys\t%S\ncpu\t%P'
Permalink to heading Don’t forget the source
command
Don’t forget the source
command
The source
command is necessary if you want to execute scripts inside other scripts or apply modifictions on the current terminal. Every time you modify your .zshrc
, run a source ~/.zshrc
to load the updated configuration.
Alternatively, you may close the current terminal and open a new one.
Permalink to heading Aliases Aliases
I love using aliases. I think that’s a great way to improve productivity and remove the hassle of remembering and typing the same command lines over and over.
Of course, Zsh allows you to set them. You can directly put them in your .zshrc
:
# π₯·π»
alias erase="history -p"
Permalink to heading Source from separate files Source from separate files
It’s fine if you have only a few aliases but I recommend using separate files to keep things organized. I usually set global aliases and specific ones, for example, aliases I use on my free time and aliases for work.
There are several approaches to achieve that but the most straightforward is to source
your additional files in the .zshrc
:
source "~/.aliases_for_work"
source "~/.aliases_for_fun"
Permalink to heading Suffix aliases Suffix aliases
You can define aliases with the -s
option:
alias -s {css,html}=vi
The above line will set vi
as editor to open .css
and .html
files.
Permalink to heading Global aliases Global aliases
Zsh allows you to define global aliases that will be expanded everywhere:
alias -g vid='-v -i --d' # letters are arbitrary here
Then you can use vid
directly in the terminal whether it’s at the beginning, in the middle, or at the end of the command line.