Shell/Scripting
This page is a reference guide to scripting-related differences between shells. It is not intended to be a general introduction to shell scripting, either in general or for a particular shell (e.g. Bash).
To check for 'bashisms', i.e. behaviour and/or functionality only found in Bash and not other shells, install the dev-util/checkbashisms package.
POSIX
- POSIX doesn't require echo to be provided as a shell builtin, only as a utility. The utility is not required to have any options.
- POSIX doesn't require printf to be provided as a shell builtin, only as a utility. The conversion specifiers defined by POSIX for the printf utility are described in the "File Format Notation" section:
a
,A
,c
,d
,e
,E
,f
,F
,g
,G
,i
,o
,s
,u
,x
,X
,%
. Additionally, theb
specifier is also defined. However, "[t]he a, A, e, E, f, F, g, and G conversion specifiers need not be supported".
Non-POSIX
The following are non-POSIX, as per Volume 3 of POSIX.1-2024, "Shells and Utilities". Note that something being specified by POSIX does not mean that all shells have necessarily implemented it (although they might plan to).
[[ ... ]]
for tests.test
/[ ... ]
should be used instead.
==
in test expressions. Instead,=
should be used to compare strings,-eq
to compare numbers.
- The
function
keyword for defining functions.
- Arrays (e.g.
$VAR[1]
) and associative arrays (e.g.$VAR['key']
).
- Process substitution, e.g.
diff <$(command one) <$(command two)
.
- Options to read other than
-r
and-d
.
- select, for creating a menu of options selectable by number.
- rehash to refresh the hash containing the locations of utilities.
hash -r
should be used instead.
- Options to the type utility. Note also that POSIX doesn't require shells to provide type as a builtin. If
type -P
functionality is required, usecommand -v
.
Introduced in POSIX-1.2024
- Dollar-single-quotes, the
$'...'
construct (e.g.$'\n'
).
- The
pipefail
shell option.
- The
-print0
option for find(1p).
- The
-d
option for the read builtin.
Ksh
The man page for app-shells/loksh, the Linux port of OpenBSD's Ksh, states:
The shell is intended to be POSIX compliant; however, in some cases, POSIX behaviour is contrary either to the original Korn shell behaviour or to user convenience.
POSIX behavior can be requested via set -o posix
or by setting the POSIXLY_CORRECT variable in the environment from which ksh is started.
Refer to the relevant section of the man page for details about behavioral changes in POSIX mode.
Zsh
- To enable POSIX-style word splitting, set the
SH_WORD_SPLIT
option.
Shell comparisons
Behavior of echo
As noted above, echo
is not required to be a shell builtin, and the echo
utility is not required to support any options. Additionally, however, the behavior of echo
varies (as at 2024-10-10):
Version | Behavior of echo '\n' |
Behavior of echo "\n" |
Behavior of echo $'\n'
|
---|---|---|---|
Bash builtin echo | $ echo '\n' \n $ |
$ echo "\n" \n $ |
$ echo $'\n' $ |
loksh (= OpenBSD ksh) builtin echo | $ echo '\n' $ |
$ echo '\n' $ |
echo $'\n' $ $ |
Zsh builtin echo | $ echo '\n' $ |
$ echo '\n' $ |
$ echo '\n' $ |
GNU utility echo | $ /usr/bin/echo '\n' \n $ |
$ /usr/bin/echo '\n' \n $ |
$ /usr/bin/echo '\n' $ |
OpenBSD utility echo | $ /bin/echo '\n' \n $ |
$ /bin/echo '\n' \n $ |
$ /bin/echo $'\n' $\n $ |
Note that, as shells are not required by POSIX to provide an echo
builtin, Dash uses the available echo
utility (i.e. by default on Gentoo, the GNU echo
utility).
All of Bash, loksh (= OpenBSD Ksh) and Zsh provide the -e
, -E
and -n
options to their echo
builtin. However, the escape sequences affected by the -e
and -E
options differ between shells:
Sequence | Description | Bash | loksh | Zsh |
---|---|---|---|---|
\a |
Alert (bell) | Yes | Yes | Yes |
\b |
Backspace | Yes | Yes | Yes |
\c |
Suppress further output | Yes | Yes | Yes |
\e |
Escape character | Yes | No | Yes |
\E |
Escape character | Yes | No | No |
\f |
Form feed | Yes | Yes | Yes |
\n |
New line | Yes | Yes | Yes |
\r |
Carriage return | Yes | Yes | Yes |
\t |
Horizontal tab | Yes | Yes | Yes |
\v |
Vertical tab | Yes | Yes | Yes |
\\ |
Backslash | Yes | Yes | Yes |
\0nnn |
The eight-bit character whose value is the octal value nnn (zero to three octal digits) | Yes | Yes | Yes |
\xHH |
The eight-bit character whose value is the hexadecimal value HH (one or two hex digits) | Yes | No | Yes |
\uHHHH |
The Unicode character whose value is the hexadecimal value HHHH (one to four hex digits) | Yes | No | Yes |
\uHHHHHHHH |
The Unicode character whose value is the hexadecimal value HHHHHHHH (one to eight hex digits) | Yes | No | Yes |
Bash vs Ksh
OpenBSD ksh (app-shells/loksh)
- As of 2024-09-23, OpenBSD ksh no longer accepts NUL bytes in scripts.
Bash vs Zsh
- Bash's builtin to set options is shopt; Zsh's analogous builtin is setopt. The list of available Zsh options is not a strict superset of Bash options; for example,
cdspell
is a Bash option but not a Zsh option.
- Zsh's alias builtin has options unavailable in Bash's alias builtin. In particular, Bash's alias only has the
-p
option, equivalent to providing no option at all, which prints defined aliases on standard output.
- The
**
syntax for 'recursive globbing' is available in Zsh by default, but is not enabled by default in Bash; it can be enabled via theglobstar
option.
- The available options for the read builtin differ between Bash and Zsh.
Bash:
read [ -ers ] [ -a aname ] [ -d delim ] [ -i text ] [ -n nchars ] [ -N nchars ] [-p prompt ] [ -t timeout ] [ -u fd ] [ name ... ]
Zsh:
read [ -rszpqAclneE ] [ -t [ num ] ] [ -k [ num ] ] [ -d delim ] [ -u n ] [ [name][?prompt] ] [ name ... ]
- Bash supports format specifications for the printf builtin which aren't supported by Zsh:
%Q
and%(<datefmt>)T
.