Shell/Scripting

From Gentoo Wiki
< Shell
Jump to:navigation Jump to:search

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).

Tip
For automated checks that scripts are not using behavior and/or functionality only found in Bash and not other shells ("bashisms"), install and use the dev-util/checkbashisms package.

The shells referenced in this page are:

Name Package Notes
Bash app-shells/bash The Bourne-Again Shell, first released in 1989; used by Portage.
Dash app-shells/dash Debian Almquist Shell; intended to be POSIX-conformant.
ATT Ksh (ksh93u+m) app-shells/ksh The original KornShell / Ksh, first released in 1983.
OpenBSD Ksh app-shells/loksh A Linux port of OpenBSD's Ksh.
Zsh app-shells/zsh The Z Shell, first released in 1990.

POSIX

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).

  • == 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).
  • 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, use command -v.
  • local, for creating a variable scoped to a function and its children. However, it is supported by Dash.

Introduced in POSIX-1.2024

  • The pipefail shell option.
  • The -d option for the read builtin.

ATT Ksh

POSIX behavior can be requested via set -o posix. Refer to the relevant section of the man page for details about behavioral changes in POSIX mode.

OpenBSD 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'


ATT Ksh builtin echo $ echo '\n'
\n
$ echo "\n"
\n
$ echo $'\n'


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, OpenBSD Ksh and Zsh provide the -e, -E and -n options to their echo builtin (although OpenBSD Ksh only treats -e and -E as options in non-POSIX mode). However, the escape sequences affected by the -e and -E options differ between shells:

Sequence Description Bash OpenBSD Ksh 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

Behavior of arrays

As arrays are not specified by POSIX, Dash doesn't support arrays.

Declaration syntax

Shell Syntax
Bash a=(1 2 3)
ATT Ksh a=(1 2 3)
OpenBSD Ksh set -A a 1 2 3
Zsh a=(1 2 3)

Subscripting syntax

By default, and after having defined an array a with the elements 1, 2, and 3:

Syntax Bash ATT Ksh OpenBSD Ksh Zsh
$a 1 1 1 1 2 3
$a[1] 1[1] 1[1] 1[1] 1
${a[0]} 1 1 1 Empty string
${a[1]} 2 2 2 1
${a[-1]} 3 3 Error 3
${a[1,-1]} 3 3 Error 1 2 3
${a[1..-1]} Error 2 3 Error Error

Zsh can be configured to use 0-based array indexing via the KSH_ZERO_SUBSCRIPT and KSH_ARRAYS options.

Additionally, when Zsh's KSH_ARRAYS option is set, braces are required when subscripting.

Behavior of pipelines

Bash, Dash and OpenBSD Ksh run the final command in a pipeline in a subshell; ATT Ksh and Zsh run the final command in the current shell. Bash's behavior can be changed via the lastpipe option.

Bash vs Ksh

ATT Ksh

  • Bash supports the local builtin, ATT Ksh does not.
  • ATT Ksh allows subscript ranges (e.g. ${a[1..-1]}), Bash does not.

OpenBSD Ksh

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 the globstar 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.

Arrays

  • Bash uses 0-based indexing, Zsh uses 1-based indexing unless the Zsh KSH_ZERO_SUBSCRIPT option or the KSH_ARRAYS option is set.
  • Bash requires curly braces around subscripted array references (e.g. ${a[1]}), Zsh does not, unless the Zsh KSH_ARRAYS option is set.
  • Zsh allows specifying subscript ranges (e.g. ${a[1,-2]}), Bash does not.