Shell DocumentationA shell is a command-line interpreter that lets users interact with the operating system by typing commands. Shells also serve as scripting environments for automating tasks. MidnightBSD includes several shells in the base system and additional shells are available through mports.
Every user account has a login shell assigned to it. When you open a terminal or log in via SSH, the login shell starts and reads its startup files before presenting a prompt. Interactive shells and non-interactive (script) shells may read different startup files, depending on the shell.
The following shells are included in the MidnightBSD base system and are available without installing any additional packages.
/bin/sh is the standard POSIX-compatible Bourne shell. It is the most portable
shell for scripting because scripts written for sh will run on virtually any
Unix-like system. MidnightBSD's sh is based on the Almquist shell (ash) and
supports the full POSIX shell specification.
sh is the recommended shell for system scripts, startup scripts, and any script
that must run in a minimal environment. It reads ~/.profile at login.
It is based on ash.
/bin/tcsh is an enhanced version of the C shell (csh) and is the
default login shell for the root account in MidnightBSD. It provides interactive features
such as command-line editing, history, and tab completion.
tcsh reads ~/.tcshrc or ~/.cshrc for interactive configuration and
~/.login at login. Environment variables are set with the setenv
command rather than the export syntax used by Bourne-compatible shells:
setenv EDITOR vim
Shell variables local to tcsh are set with set:
set prompt = "%n@%m %~ %# "
/bin/mksh is the MirBSD Korn Shell, a lightweight and standards-compliant
implementation of the Korn shell. It is compatible with POSIX sh and supports
many ksh extensions such as arrays, arithmetic expressions, and associative
arrays. It is a good choice for scripting when you need features beyond POSIX sh
but want to avoid a dependency on bash.
mksh reads ~/.mkshrc for interactive configuration.
More shells are available through mports. After installation each shell's path must be listed
in /etc/shells before it can be set as a login shell. Shells installed from
mports are typically placed under /usr/local/bin/.
bash is the most widely used shell on Linux systems and is familiar to many users. It supports interactive features such as readline editing, history expansion, job control, arrays, and extensive scripting extensions beyond the POSIX standard.
Install bash from mports:
mport install bash
bash reads ~/.bash_profile or ~/.profile at login and
~/.bashrc for interactive non-login shells.
zsh is a powerful interactive shell with extensive customization options, advanced tab
completion, spelling correction, theme support, and compatibility with both sh
and ksh syntax. It is the basis for popular frameworks such as Oh My Zsh.
Install zsh from mports:
mport install zsh
zsh reads ~/.zshenv always, ~/.zprofile at login, and
~/.zshrc for interactive shells.
fish is designed for ease of use out of the box. It provides syntax highlighting as you type,
autosuggestions based on history, and web-based configuration. fish does not aim to be POSIX
compatible and uses its own scripting syntax, so sh scripts cannot be sourced
directly.
Install fish from mports:
mport install fish
fish reads ~/.config/fish/config.fish for interactive configuration.
The /etc/shells file lists the shells approved for use as login shells on the
system. Only paths listed in this file may be selected with chsh. A typical
/etc/shells looks like:
# List of acceptable shells for chpass(1). # Ftpd will not allow users to connect who are not using # one of these shells. /bin/sh /bin/csh /bin/tcsh /bin/mksh /usr/local/bin/bash /usr/local/bin/zsh /usr/local/bin/fish
When you install a shell from mports it is usually added to /etc/shells
automatically. If it is not, add the full path manually as root using your preferred editor.
Use chsh to change your login shell. Running it without arguments opens an
editor where you can change your shell entry:
chsh
You can also pass the new shell path directly with the -s flag:
chsh -s /usr/local/bin/bash
To change another user's shell, root may specify the username:
chsh -s /usr/local/bin/zsh username
The change takes effect at the next login. To verify the current login shell for a user:
getent passwd username
Or check your own:
echo $SHELL
Environment variables pass configuration and state information to processes. They are inherited
by child processes. In Bourne-compatible shells (sh, bash,
zsh, mksh) variables are exported with the export
command. In tcsh, use setenv.
Set and export a variable in sh/bash/zsh/mksh:
export VARNAME="value"
Set a variable in tcsh:
setenv VARNAME "value"
List all current environment variables:
env
Print a single variable:
echo $VARNAME
EDITOR specifies the non-visual fallback text editor used by programs such as
crontab -e, svn commit, and various other utilities when they need
to open an editor. It is typically set to a simple terminal editor.
export EDITOR=vi
VISUAL specifies the preferred full-screen visual editor. Many programs check
VISUAL first and fall back to EDITOR if it is not set. Set it to
a full-featured editor such as vim, nano, or emacs.
export VISUAL=vim
HOME is the path to the current user's home directory. It is set automatically
at login from the password database entry. The tilde (~) shorthand in shells
expands to the value of HOME.
echo $HOME
PATH is a colon-separated list of directories the shell searches when looking
for commands. Adding a directory to PATH makes executables in that directory
available without specifying the full path.
export PATH="$PATH:/usr/local/bin:/usr/local/sbin"
MANPATH is a colon-separated list of directories searched by man
when looking for manual pages. If unset, man uses a built-in default. Set it
when you have manual pages installed in non-standard locations.
export MANPATH="/usr/share/man:/usr/local/share/man"
PAGER specifies the program used to display output one screen at a time.
Commands like man use PAGER to display their output. The default
is usually more; less is a popular alternative that supports
backward scrolling.
export PAGER=less
TERM identifies the terminal type, which tells programs how to control the
display (cursor movement, colors, clearing the screen, etc.). It is normally set automatically
when you log in or open a terminal emulator. Common values are xterm,
xterm-256color, and vt100. Setting it incorrectly can cause
display corruption in full-screen programs like vi and top.
export TERM=xterm-256color
COLORTERM tells color-aware applications whether the terminal supports
24-bit (truecolor) output. Terminal emulators that support truecolor set this to
truecolor or 24bit. Many modern applications such as vim, neovim,
and tmux check this variable to decide whether to use full RGB colors.
export COLORTERM=truecolor
LSCOLORS controls the colors used by ls on BSD systems when the
-G flag is used. Each pair of characters encodes the foreground and background
color for a file type. Linux-style tools may use LS_COLORS instead, which uses
a different format understood by the GNU dircolors utility.
export LSCOLORS=ExFxCxDxBxegedabagacad
LANG sets the default locale, which affects character encoding, date formatting,
number formatting, and message language for locale-aware programs. More specific locale
categories can be overridden individually with variables such as LC_ALL,
LC_CTYPE, and LC_MESSAGES.
export LANG=en_US.UTF-8
TZ overrides the system timezone for a single user or process. The value should
be a timezone name from /usr/share/zoneinfo.
export TZ=America/New_York
TMPDIR specifies the directory used for temporary files created by programs and
shell scripts. If unset, /tmp is used. Changing it is useful when /tmp
is small and a larger scratch space is available elsewhere.
export TMPDIR=/var/tmp
Pipes and redirection are fundamental shell features that control where command input comes from and where output goes. They work the same way across all shells covered in this document.
Every process has three standard streams:
Redirect stdout to a file, creating or overwriting it:
command > output.txt
Append stdout to a file instead of overwriting:
command >> output.txt
Redirect stderr to a file:
command 2> errors.txt
Redirect both stdout and stderr to the same file:
command > output.txt 2>&1
Discard output by redirecting to /dev/null:
command > /dev/null 2>&1
Redirect a file to stdin so the command reads from it instead of the keyboard:
command < input.txt
A here-document feeds multiple lines of text directly to a command's stdin. The delimiter
(EOF in this example) marks the end of the input:
command <<EOF line one line two EOF
A here-string passes a single string as stdin (supported in bash, zsh, mksh, and ksh):
command <<< "some text"
A pipe (|) connects the stdout of one command to the stdin of another, letting
you chain commands together to process data in stages:
command1 | command2
Chain multiple commands:
cat /var/log/messages | grep error | sort | uniq -c | sort -rn
To pipe both stdout and stderr through a pipe, redirect stderr to stdout first:
command 2>&1 | less
In most shells, the exit status of a pipeline is the exit status of the last command. In
bash and zsh, you can enable the pipefail option so the pipeline fails if any
command in it fails:
set -o pipefail
Command substitution captures the output of a command and uses it as a value in another
command. The preferred modern syntax uses $():
today=$(date +%Y-%m-%d)
echo "Files: $(ls | wc -l)"
The older backtick syntax is equivalent but harder to nest:
today=`date +%Y-%m-%d`
Process substitution (supported in bash and zsh) treats the output of a command as if it were a file. This is useful when a command requires a filename argument but you want to feed it the output of another command:
diff <(sort file1.txt) <(sort file2.txt)
The tee command reads from stdin and writes to both stdout and one or more files
at the same time. This lets you view output in the terminal while also saving it:
make 2>&1 | tee build.log