The Z-shell (zsh) is a modern and very powerful shell: it incorporates and extends many feature of other shells, like Bash. Although it can be used as a powerful scripting language, it is mainly aimed at interactive use, since one of its more prominent feature is the advanced tab completion system. In this tutorial we see how to install zsh in the most commonly used Linux distributions, see what are its startup and shutdown files and how to perform the basic configurations.
In this tutorial you will learn:
- How to install Zsh on the most used Linux distributions
- What is the difference between interactive,non-interactive, login and non-login shells
- What are the Z-shell startup and shutdown files and in which context they are invoked
- How to perform the basic shell configurations
- How to setup PATH when using zsh
- How to set zsh as the default shell

Software requirements and conventions used
Category | Requirements, Conventions or Software Version Used |
---|---|
System | Distribution-independent |
Software | zsh |
Other | Root privileges for installation |
Conventions | # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command$ – requires given linux-commands to be executed as a regular non-privileged user |
Installing Zsh
Performing the installation of Zsh is a very easy task, since it is available in the official repositories of the most used Linux distributions. To install the package on Debian or one of the many systems based on it, we should run:
$ sudo apt-get update && sudo apt-get install zsh
To perform the installation on Fedora, instead, we would use the dnf
package manager:
$ sudo dnf install zsh
On Archlinux, instead, to install software packages, we use
pacman
:
$ sudo pacman -Sy zsh
Few seconds and zsh should be installed. Before start talking about how to configure it, let’s take a moment to remark the distinction between the different “type” of shells we can use; this will help us understand the role of zsh startup files.
Type of shells
We can basically distinguish the following shell types:
- interactive
- non-interactive
- login
- non-login
An interactive shell, as its name suggests, is what we normally use when we launch a terminal emulator: its input and error outputs are connected to said terminal. A non-interactive shell, instead, doesn’t accept user input. When a command is launched from inside a script, for example, a non-interactive shell is used.
The further distinction we have, is between login and non-login shells. A login shell is what is invoked when we login into the system via a TTY or via ssh. In such cases we are working in an interactive login shell. A non-login shell, instead, is any other type of shell used once we are logged into the system (unless a login shell is invoked explicitly).
Grasping the above distinctions will help us better understand in what context zsh startup files are used. Let’s see what they are.
Zsh startup and shutdown files
The system-wide zsh startup files are the following:
- /etc/zshenv
- /etc/zprofile
- /etc/zlogin
- /etc/zshrc
- /etc/zlogout
Each one of the files above have its per-user equivalent. User-level configuration files are located in the directory path set as value to the ZDOTDIR
variable. If the value of this variable is an empty string, files are assumed to be in the user HOME
directory. Per user configuration file names starts with a .
, so they are hidden (dotfiles):
- .zshenv
- .zprofile
- .zlogin
- .zshrc
- .zlogout
The /etc/zshenv
and .zshenv
configuration files are used to define environment variables. They are always invoked each time a zsh session is started, therefore they should contain the less possible content. Only commands that don’t produce output should be written in these files.
The /etc/zprofile
and .zprofile
startup files are read when a login shell session is started, and can be used to run commands to setup that specific context. When using interactive shells they are executed before /etc/zshrc
and .zshrc
.
The /etc/zlogin
and .zlogin
files, are invoked when login shell sessions are started too. When using interactive shells, however, they are executed after /etc/zshrc
and /.zshrc
. While they can be used together with the “profile” files, should be considered as an alternative to them.
The /etc/zshrc
and .zshrc
files are invoked when an interactive shell session is started. They are basically the counterpart of the /etc/bashrc
and ~/.bashrc
files for the BASH shell.
Finally, the /etc/zlogout
and .zlogout
files are run when a login shell session is closed. The latter is run before the former.
System-wide configuration files are read before their user-only counterpart, so here is the global order in which configuration files are read. When using interactive, non-login shell sessions:
- /etc/zshenv
- ~/.zshenv
- /etc/zshrc
- ~/.zshrc
When using interactive, login shell sessions:
- /etc/zshenv
- ~/.zshenv
- /etc/zprofile
- ~/.zprofile
- /etc/zshrc
- ~/.zshrc
- /etc/zlogin
- ~/.zlogin
- ~/.zlgout
- /etc/zlogout
When using non-interactive, non-login shell sessions (for example when a command is launched from a script):
- /etc/zshenv
- ~/.zshenv
First zsh configuration
The first time we start an interactive zsh shell session (for example by running zsh
in a terminal), if no configuration files exist for our user, the zsh-newuser-install
script is launched. It is meant to help us creating our first setup:

As we can see, to proceed we just should press (1)
. If we decide to do so, we will be prompted to select what aspect of the shell we want to configure:

My suggestion is to proceed with the basic setups, and than examine what is generated in the startup files in order to better understand how things work under the hood. Once this is done, we can always tweak things further, by, for example, looking at other users configuration files stored on github, or similar sites.
Configuring history
To configure how history is handled we would press (1)
when the above menu is displayed. This would lead us the to the following screen:

The value of three environment variables is displayed. We talked about how to configure bash history in a previous tutorial, so those variables should appear familiar to us. The first one HISTSIZE
, contains the number of lines of history which are kept in memory, the second, HISTFILE
is used to define in what file history is saved when the shell session is closed. Finally, the value of the third, SAVEHIST
, is the number of lines to be kept in the history file.

To edit one of those values, all we have to do is to press the corresponding key. For example, to change HISTSIZE
we would press (1)
. We will be prompted to insert the desired value:
Settings are not permanently saved until we return to the main menu (0)
and choose (0) Exit, saving the new settings...
again.
Configuring the PATH
As we know, the PATH
environment variable contains the list of directories in which programs and executables are searched by default, so that they can be launched without having to specify their absolute path. The method we use to add directories to our PATH
when using Bash is to list them separated by the :
character in the ~/.bash_profile
file. For example to add the ~/.local/bin
directory to our PATH we would write:
export PATH="$HOME/.local/bin:$PATH"
When using zsh, we define our PATH
in a different way. Directories which should be included are specified using an array inside the ~/.zshenv
file. To do the same thing we did in the previous example, we would write:
path=("$HOME/.local/bin" $path)
With the above configuration a problem would arise, since at each invocation of the .zshenv
file ${HOME}/.local/bin
would be added to the array, which would contain many duplicates. To solve this problem we have to use the following line before the array declaration:
typeset -U path
What the typeset -U path
line does is simply avoiding duplicates inside the array. The leftmost element is kept in the array if another one already exists. Imagine the array contains the following directories (notice the %
symbol in the prompt when we are using zsh):
% echo $path /home/egdoc/.local/bin /home/egdoc/bin /usr/local/bin
If we add again the /usr/local/bin
element to the beginning of the array, the old occurrence is removed:
% typeset -U path % path=(/usr/local/bin $path) % echo $path /usr/local/bin /home/egdoc/.local/bin /home/egdoc/bin
Using zsh as the default shell
To change the default login shell for a user, we use the
chsh
command. We invoke it with the -s
(--shell
) option, and pass the path of the shell we want to use as argument. In our case we want to set /bin/zsh
as our default shell, therefore we run:
$ chsh -s /usr/bin/zsh
Conclusions
In this tutorial we learned the basics of zsh, a modern shell with many features like advanced tab completion. We saw how to install it on the most used Linux distributions, what are the zsh startup files and in what context they are invoked, how to perform the basic shell configurations, how to setup PATH with zsh, and, finally, how to set zsh as the default login shell.