Bourne
| Ash
| #!
| find
| ARG_MAX
| Shells
| portability
| permissions
| UUOC
| ancient
| -
| ../Various
| HOME
"$@"
| echo/printf
| set -e
| test
| tty defs
| tty chars
| $() vs )
| IFS
| using siginfo
| nanosleep
| line charset
| locale
Ash (Almquist Shell) Variants
2010-01-31 (see recent changes)
After I had repeatedly wondered how all those "ash" variants
might be related, I had a look at the variants I know.
Source is available for all variants, except for BSD/OS.
Thanks to TUHS for archiving the traditional BSDs and 386BSD,
to Kirk McKusick for his CSRG archive,
and to Peter Seebach for allowing me to learn all BSD/OS variants.
This page documents relationships. For the variants without changelogs
(the traditional BSDs, 386BSD, BSD/OS and Minix) this page aims at being a complete log
(with emphasis on the source).
For the other variants this was certainly not the goal and just some
arbitrarily chosen changes or bugfixes are listed.
Content:
· 1.) Original release '89
· 2.) Traditional BSDs:
4.3BSD-Net/2 '91,
4.4BSD-Alpha '92,
4.4BSD '93,
4.4BSD-Lite '94,
4.4BSD-Lite2 '95
· 3.) 386BSD '92-'93
· 4.) BSD/OS (BSDi) '91-'03
· 5.) NetBSD '93-
· 6.) FreeBSD '96-
· 7.) early port from NetBSD to Linux '93 (and early Slackware, Debian)
· 8.) dash '97- (and later Slackware)
· 9.) Slackware variant of dash '06-
· 10.) BusyBox '01-
· 11.) Minix '01-
Here's an illustration of the family tree (click for increased size).
1.) Original release ('89) - sh(1)
It was written by Kenneth Almquist as replacement to the
traditional "System V Release 4" Bourne shell
due to the license war between AT&T and Berkeley.
Berkeley distributed it first with "BSD 4.3-Net/2".
The source was
posted to comp.sources.unix, "A reimplementation of the System V shell", on 30-05-1989.
Shortly after, Kenneth published a
job control patch
to fix the problem that more than 4 jobs were not handled properly.
Differences between the ash family and the SVR4 shell:
- implements "
$(...)" command substitution
- accepts "
export VAR=value"
- in a for loop, "
{ ... }" is recognized as body like
"do ... done" (exception: dash-0.3.8-1 ff.)
-
echo (silently) accepts option -e (undocumented)
- the file DIFFERENCES from the original distribution
lists most remaining differences to both the Berkeley shell
(a variant of the V7 shell) and the SVR4 shell.
- naturally, nothing from the list of
specific Bourne shell behaviour is implemented.
- last but not least, one difference is even a characteristic feature of almquist shells in general:
a PATH component flagged with a trailing "%func" is recognized
as a directory containing function definitions. Read more about this.
Common to the original Almquist shell and the SVR4 shell, but changed with later ash variants:
- no command line editing and history (by intention)
- no # and % form of parameter expansion
- no arithmetic expansion
- "
set --" doesn't unset the parameter list
- traditional behaviour about
IFS vs. "$*"
Common to ash variants and the SVR4 shell only, in contrast to other bourne compatible shells:
- "
notexistent_cmd 2>/dev/null" doesn't redirect the error "not found"
(exception: dash since 0.4.17)
- "
echo x > file*" doesn't expand file*
Details which are only found in early ash variants:
- (only) the original release knew an undocumented version variable:
SHELLVERS=ash-0.2
later variants can only be recognized by characteristic features.
- by intention, there is no backslash escaping in the back-tick form of
command substitution (
`...`), side effect: this form cannot be nested [4.4BSD]
- undocumented: no "type" built-in (probably accidentally) [NetBSD1.3,FreeBSD2.3]
- read by default behaves as if the POSIX flag "-r" is active
- PS1 is "@"
- "with sh -c cmd arg0 arg1, $1 is set to arg0" (fixed relatively late:
all traditional BSDs, and early Free-/NetBSDs and early Minix
behave as well)
- bug: "
VAR=set eval 'echo $VAR'" gives no output,
that is, you can't call eval with local variables
- flag "v" not implemented
- "
for i do" not accepted
(but "for i; do" or "for i<newline>do")
- reads SHINIT at start
(except if a login shell or called with "sh file")
- "trap" doesn't accept symbolic signal names
- "expr" is a built-in, merged with "test"
- negation of patternmatching with "!!pattern"
- flag z (don't leave pattern after redirection unchanged if it doesn't match)
- rejects "
case x in (x)"
[1]
(Fixed soon. As exceptions, NetBSD and Minix fixed this quite late)
- bug: segmentation violation on empty command substitution "
$( )"
(but not on "` `")
- bug: segmentation violation on "
${var=`cmd`}"
- bug: built-ins in command substitution are wrongly optimized,
the shell exits upon
foo=`exit 1` [NetBSD 1.4]
- compile time option (off by default) for a "cleaner" eval (not concerning the above problem, though)
- shell recognizes #! (if the kernel fails), if not compiled with BSD support
This compile time macro is explained with "running 4.2 BSD or later".
This code still exists in some modern variants, but is de-facto inactive.
| [1]
| In fact, no ash variant needs "case x in (x)" because the
parser is robust about case constructs in $(...) command substitution.
However, several other shells are not robust and they have to
work around it this way; so this is a script portability issue.
It was, sooner or later, fixed in most implementations:
BSD/OS 3.0 (06/'96), dash-0.3.5-4 (08/'99) (and thus Busybox and Slackware 8.1 ff.),
FreeBSD 4.8/5.1 (10/'02), NetBSD 4.0 (06/'06).
|
2.) Traditional BSDs ('91-'95)
4.3BSD-Net/2 (06/'91) - sh(1)
- PS1 depends on uid
- in contrast to the original distribution,
echo doesn't interpret escape sequences by default on BSDs,
but requires -e
- not only "--", but also "-" terminates options
- shell version variable
SHELLVERS=ash-0.2 removed
- undocumented: flag v becomes a synonym for x
- compile time option for different parsing in eval removed
- the abovementioned job control patch is applied.
- built-in "bltin" renamed to "command"
- built-ins "catf", "expr", "line", "nlecho" removed
- "chdir" becomes synonym for "cd"
- A user without HOME starts in /tmp instead of / (except uid 0).
4.4BSD-Alpha (06/'92) - starts aiming at POSIX.2 - sh(1)
- history and line editing
(fc, $FCEDIT, $HISTSIZE, flags E and V)
and atty support removed (optional support by terminal driver)
- arithmetic expansion "$((...))"
- built-in "printf"
- negation of pipeline with !
- tilde expansion added, /u/logname mechanism removed
- aliases
- "set -o" prints options
- "cd -" added
- reads ENV instead of SHINIT at start
- renamed flag j (jobcontrol) to m (like SVR4 shell),
added flags C (noclobber), a (allexport), b (notify asynchronous jobs),
removed flag z,
added but not implemented flag u (error on unset)
- warning "You have stopped jobs."
- "shift" built-in knows "can't shift that many"
- warning "running as root with dot in PATH" in case
- negation of patternmatching with "!!pattern" removed
- bugfix: accepts empty command substitution "
$( )"
- manual page completely rewritten
- ... and the
%func/%builtin
functionality was removed from the manual but not from the code
- ... and note that the
# and % forms of
parameter expansion are documented as unimplemented
4.4BSD (06/'93) - sh(1)
Apparently, the
386BSD patchkit 2.4
(local copy) went into this release or vice versa:
- escaping in back-tick command substitution (
`...`) "re-introduced",
thus back-ticks become nestable
- accepts "for i do"
- backquoted commands set $?
- do not redirect STDIN of background commands to /dev/null
if it has been redirected previously
- bugfix about escaping in quoted variables and case switch
- redirections may precede non-simple commands
and:
- extended copyright message and the sccsid in all files
- "wait" yields an exit status
- "fc" knows "missing history argument"
- handles the empty command like other simple commands, allows "if ; ..."
4.4BSD-Lite (06/'94) - sh(1)
- "read" errors with "arg count" if called without arguments.
The code was already there but a bug caused a SEGV only.
- bugfix in conditional parameter expansion, e.g. "
${var=`cmd`}" is accepted
4.4BSD-Lite2 (06/'95) - sh(1)
This release has synched with NetBSD at about 05/'95.
- parameter expansion knows # and %
- "ulimit" built-in added
- "printf" built-in removed
- arithmetic expansion accepts binary logic operators (&, |, ^, ~)
- "umask" understands symbolic notation
- PATH assigment preceding a command is even regarded for the lookup
- source command does path lookup for executable files
- fix about saved exit status
(examples: "
false; echo `echo $?`; false || foo=bar; echo $?; foo=; false; $foo; echo $?")
- leading colon in default PATH removed (influences restricted mode)
- doesn't warn root anymore if PATH contains a dot
- Only look up ENV at startup if IDs equal effective IDs
- "false" built-in added ("true" already was handled equal to ":")
- dash can be escaped in range, like [a\-z]
- empty command, e.g. "if ; ...", not allowed anymore
3.) 386BSD ('92-'93) - sh(1)
The 386BSD distribution was derived from 4.3BSD-Net/2 and aimed at maintaining a runnable system,
that is, completing Net2 with the pieces which had to be removed after the license war.
- 386BSD 0.0: initial release (02/'92)
- 386BSD 0.1: "cd" doesn't print target directory (CDPATH, symlinks)
- patchkit 2.3 (04/'93): fix for "cd" (when internally calling pwd(1))
- patchkit 2.4 (06/'93) (local copy)
- escaping in back-ticks fixed, thus back-ticks become nestable
- accepts "for i do"
- backquoted commands set $?
- do not redirect STDIN of background commands to /dev/null
if it has been redirected previously
- bugfix about escaping in quoted variables and case switch
- redirections may precede non-simple commands
See the 386BSD archive on TUHS.
4.) (BSDi) BSD/OS ('92-'03)
This is a commercial BSD branch from the vendor BSDi.
And the vendor F5 for example uses a BSD/OS 4.1 as core for its product BIG-IP 4.2.
- initial release taken 01/'92 from 4.3BSD-Net/2.
With some tiny changes this becomes BSD/OS 1.0 (03/'93).
- BSD/OS 1.1 (01/'94)
- resynchronized with 4.4BSD, and
- csh-like "limit/unlimit" added
- restricted functionality added
- "case" improved (POSIX: don't recognize keywords in patterns)
- bug in redirection fixed
- bugfix for "set -a"
- noninteractive shell handles SIGINT not until cmd terminated
- BSD/OS 2.0 (02/'95)
- resynchronized with 4.4BSD-Lite, and earlier BSD/OS-specific changes re-added
- Get IFS delimiters using POSIX.2 rules
- POSIX made ":" a special builtin, now it behaves different from "true" on errors
- fix about return value of "unset" under special conditions
- fix restricted mode: apart from /cmd also deny ./cmd
- fix internal types (now unsigned) in resource consumption output
- BSD/OS 2.1 (03/'95)
- tiny fix for "fc" history built-in (NULL argument)
- BSD/OS 3.0 (06/'96)
- resynchronized with 4.4BSD-Lite2, and earlier BSD/OS-specific changes re-added,
- ...thus the "printf" built-in disappears again
- (exception: main.c is 8.7 7/19/'95" instead of "8.6 5/28/'95" in 44BSD-Lite2)
- redirection "<>" added
- accepts "case x in (x)"
- fix about matching a backslash-escaped dot
- some fixes about dereferencing null pointers
- bugfixes with "showtree" output (compile time debug option)
- BSD/OS 4.0 (02/'98) - and BIG-IP 4.2 (BSD/OS 4.1 derived, vendor is F5)
- "test" built-in added
- fixes for "getopts" (OPTIND variable, error prints script name instead of "getopts")
- fix for exit status of "return" (built-ins)
- fixes in redirection code (closing file descriptors)
- a fix for restricted mode
- unused #! support removed
- BSD/OS 5.0 (05/'02)
- fix for "cd" (when internally calling pwd(1))
- BSD/OS 5.1 (05/'03)
- flag -r added (to sync with POSIX); former "read" flag -e becomes default
Thus, there remain for example the following differences
to modern variants:
- no "type" built-in
- "trap" doesn't accept symbolic names
- old behaviour about
IFS vs. "$*"
5.) NetBSD ('93-current)
Initially derived from 386BSD-0.1,
soon synchronized with 4.4BSD-Lite.
- initial import from 386bsd-0.1, 03/'93
- "umask" accepts symbolic notation, 07/'93, NetBSD 1.0
- "false" built-in, 07/'93, NetBSD 1.0
- synch with 4.4BSD-Lite, 05/'94, NetBSD 1.0
- "ulimit" built-in, 11/'94, NetBSD 1.2
- # and % parameter expansion, 01/'95, NetBSD 1.2
- with "sh -c cmd arg0 arg1", $1 is set to arg1, 10/'96, NetBSD 1.2
- "type" built-in added, 02/'97, NetBSD 1.3
- modern behaviour about IFS vs. "$*",
07/'97 for NetBSD 1.3
- "read -r", 11/'97, NetBSD 1.3 (formerly it behaved so by default)
- "trap" accepts symbolic names (and more fixes), 03/'01, NetBSD 1.6
- "set -u" actually implemented, 03/'02, NetBSD 1.6
- "printf" built-in added, 11/'02, NetBSD 2.0
- arithmetic expansion accepts variable names without dollar, 03/'05, 3.1/4.0
CVS-Web
on netbsd.org.
6.) FreeBSD ('94-current)
Derived from 4.4BSD-Lite,
-Lite2
and NetBSD 1.2/1.3
- initial import from 4.4BSD-Lite 05/'94
- with "sh -c cmd arg0 arg1", $1 is set to arg1, 10/'95, FreeBSD 2.1
- merge in sources from 4.4BSD-Lite2, 05/'96+10/'96, for FreeBSD 2.2
- merge in NetBSD (~1.2) sources, 12/'96, for FreeBSD 2.2
- "trap" accepts symbolic names, 12/'96, FreeBSD 2.2
- "type" built-in added (from NetBSD), 04/'97, FreeBSD 2.2.5
- [^...] negation, 6/'97, FreeBSD 2.2.5
- import expand.c from NetBSD ~1.3, 04/'97, ~FreeBSD 3
- modern behaviour about
IFS vs. "$*", 09/'98, FreeBSD 3.1
- "read -r", 09/'99, FreeBSD 3.3 (formerly it behaved so by default)
- "VAR=set eval 'echo $VAR'" prints "set" instead of nothing, 05/'00, FreeBSD 4.6/5.0
- "set -u" actually implemented (see NetBSD), 03/'02, FreeBSD 4.7
- arithmetic expansion accepts variable names without dollar, 08/'03, 5.2
CVS-Web
on freebsd.org.
7.) Early port of a NetBSD variant to Linux ('93)
Contributions by e.g. Sunando Sen, Arjan de Vet, Florian La Roche.
This earlier port is not related to the later
dash from Herbert Xu.
- v0.0 08/93: imported NetBSD sh variant 19930810
(~NetBSD 1.0, that is, close to 386BSD, and thus even close to 4.3BSD-Net/2)
- v0.1 08/93: test built-in, set -u, executable permission problem fixed
- v0.2 09/93: 19930918 NetBSD sources re-imported and re-patched
(still close to 386BSD)
Thus this variant is still very close to 4.3BSD-Net/2 and even the original version.
Several distributions came with this variant:
- Slackware 2.1 ('10/'94) switched from bash-1.x to this variant.
Release 7.0 added a tiny patch to fix compiling problems.
Via slackware.org mirrors to
slackware-3.3/source/ap/ash/
- Debian came with this variant until the stable release 1.3.1 ("Bo")
- The T2 SDE project uses this shell.
ash-linux-0.2 tarball on metalab.unc.edu.
This started as a Linux port for Debian, from Herbert Xu, derived from NetBSD.
And Debian stable release 2.0 ("Hamm", 03/'99) then replaced the early Linux port ash-0.2 with this variant.
Two high priorities of this project are restricting to POSIX conformance and slim implementation.
The Ubuntu distribution switched to dash
as system shell with release 6.10 (10/'06).
Ubuntu dash packages are available here.
In the Debian distribution, one of the release goals
(wiki.debian.org,
release.debian.org)
for the release Lenny was switching to dash as system shell. This move was postponed, though.
The dash manual documents the command line history and editing capabilities (gained with 4.4BSD-Alpha).
These features are disabled at compile time, though.
You can enable them by recompiling: have the "BSD editline and history library" available
(package libedit-dev on Debian) and remove -DSMALL from src/Makefile.
- fork from NetBSD-current-19970715 (~ release 1.3).
It starts as "ash" release with release number "0.3-1"
It gets re-synced with NetBSD later several times.
- Sync with NetBSD on 19970715, 19980209.
- [Debian stable release 2.0 ("Hamm") 03/'99 with ash_0.3.4-2]
- [Debian stable release 2.1 ("Slink") 08/'99 with ash_0.3.4-6]
- echo doesn't accept "-e" anymore, 10/'99, 0.3.5-7
- [Debian stable release 2.2 ("Potato") 08/'00 with ash_0.3.5-11]
- substituted the embedded
pmatch() with fnmatch(3) as of 0.3.7-1,
but switched this several times later (due to problems with buggy glibc versions).
This also determines if extended character classes
like [:print:] are recognized
- "printf" built-in added, 04/'01, 0.3.8-1
- doesn't recognize "{ ... }" any longer as body in a
for loop
(that is, as "do ... done"), 04/'01, 0.3.8-1
- Sync with NetBSD on 20000326, 20000729, 20010316 and patches from NetBSD on 20010502, 20011103, 20020302.
- [Debian stable release 3.0 ("Woody") 07/'02 with ash_0.3.8-37]
- renamed to "dash" (influenced by Debian), 09/'02, with release 0.4.1.
- [Debian stable release 3.1 ("Sarge") 06/'05 with dash_0.5.2-5]
- Sync with NetBSD 1.6 on 20021019.
- "
notexistent_cmd 2>/dev/null" redirects the error "not found" since 12/'02, 0.4.7.
- Sync with NetBSD on 20030123.
- As of 0.4.26-1 (2004-05-28) it's not a native debian package anymore
but is maintained independently (and debian maintenance goes to Gerrit Pape).
- added extended character classes due to still existing problems with glibc
fnmatch(),
06/'04, 0.4.26.
- [Debian stable release 4.0 ("Etch") 04/'09 with dash_0.5.3-7]
- arithmetic expansion accepts variable names without dollar, 01/'09, 0.5.5.1.
- [Debian stable release 5.0 ("Lenny") 09/'09 with dash_0.5.4-12]
Herbert Xu's dash,
Debian package.
For the changelogs, see ./Changelog (0.5.5.1 snapshot)
and the older ./debian/changelog (snapshot)
in the distribution.
9.) Slackware variant of debian ash ('06-current)
Slackware 2.1 ('10/'94) had switched to the abovementioned
early ash-linux-0.2 port.
Slackware 8.1 (09/'06) switched to debian ash-0.4.0 and a collection of 21 debian patches,
(with the debian specific stuff taken out)
With later releases, these patches were not modified anymore.
Some other smaller distributions, emphasizing on a slim shell, also use the Slackware shell variant.
Via slackware.org mirrors to
slackware-current/source/ap/ash/
10.) BusyBox ('01-current)
The BusyBox distribution
is aiming for small implementations.
- The debian ash variant 0.3.8-5
was incorparated with busybox release 0.52 (07/'01).
(This release also added msh (the minix shell) and lush ["a work in progress"]).
- ash became the default shell with busybox release 0.60.3 (04/'02).
- compile time options to deactivate jobcontrol, math and several
built-ins (alias, getopts, echo, test, command, chdir, some flags for read;
in earlier busybox versions even also true, false, type, chdir).
- undocumented: calls fnmatch(3) instead of the embedded pmatch(),
which is problematic due to bugs in some glibc versions.
This also introduces [^...] as synonym for [!...].
11.) Minix ('01-'06/'06-current)
Sven Mascheck, <http://www.in-ulm.de/~mascheck/various/ash/>