After I had repeatedly wondered how all those "ash" variants
might be related, and had found hardly any information, I had a closer 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.
And for the variants without changelogs (the traditional BSDs, 386BSD, BSD/OS and Minix)
this page aims at being a complete log concerning source code changes.
But for the other, later variants this was certainly not the goal and just a few,
arbitrarily chosen changes or bugfixes are listed.
Why no commented diffs? I won't manage to do that work. And if you're interested
on this level, then you are looking at the source already and these comments are a good start.
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.
First, a few summaries for orientation, what it's about with these almquist shells.
Differences between the ash family and the SVR4 shell:
ash implements "$(...)" command substitution
accepts "export VAR=value"
echo accepts option -e to interpret escape sequences (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.
A few differences are documented but not listed in this file, e.g.,
the built-ins "bltin" and "setvar"
only mentioned in the manual, but not explained:
built-ins "catf", "expr", "line", "nlecho"
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.
another characteristic feature of almquist shells:
"local -" makes $- local in functions (thanks to Jilles Tjoelker)
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 and FreeBSD 9.0)
"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 and distinguished by characteristic features.
(A release "ash-0.2" of the later linux port is not related to this variable.)
like SVR4 sh: no command line editing and history (by intention)
like SVR4 sh: no # and % form of parameter expansion
like SVR4 sh: no arithmetic expansion
like SVR4 sh: no multi-digit parameter expansion like ${10}
like SVR4 sh: "set --" doesn't unset the parameter list
like SVR4 sh: traditional behaviour about
IFS vs. "$*"
by intention, there is no backslash escaping in the back-tick form of
command substitution (`...`), side effect: this form cannot be nested [changed in 4.4BSD]
undocumented: no "type" built-in (probably accidentally) [fixed in 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
"for i do" not accepted
(but "for i; do" or "for i<newline>do")
flag -v not implemented
reads SHINIT at start
(except if a login shell or called with "sh file")
"trap" doesn't accept symbolic signal names
"expr" built-in, merged with "test"
negation of patternmatching with "!!pattern"
flag -z (don't collapse filename pattern 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`}"
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 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).
Details which are found in early and in some later ash variants:
bug: built-ins in command substitution are wrongly optimized,
the shell exits upon foo=`exit 1` [fixed in NetBSD 1.4, dash-0.3.5 and thus busybox, FreeBSD 9.0]
A detail which is found in ash, in the SVR4 shell,
and in most bourne compatible shells, but usually not documented
accepts "{ ...; }" as body in a for loop (instead of "do ...; done")
renamed flag -j (jobcontrol) to -m (like SVR4 shell),
added flags -C (noclobber), -a (allexport), -b (notify asynchronous jobs),
implemented and documented flag -v (formerly accepted but not implemented),
removed flag -z, (don't collapse filename pattern if it doesn't match)
accepted (document as not implemented) flag -u (error on unset)
documents multi-digit parameter substitution, like ${10}, but doesn't implement it
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 "$( )"
"lc" built-in removed
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
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, sh is identical to 4.3BSD-Net/2 (02/'92)
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
(wiki.ubuntu.com)
as system shell (/bin/sh) with release 6.10
(october '06).
The Debian distribution switched to dash with the release
6.0/"Squeeze"
(release goals,
Debian shells).
(It was a release goal for Lenny already,
but the move was postponed, then).
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.
Some changes:
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 0.3.4-2]
[Debian stable release 2.1 ("Slink") 08/'99 with 0.3.4-6]
[Debian stable release 2.2 ("Potato") 08/'00 with 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 negation with [^...] and extended character classes
like [:print:] are recognized
previous exit status preserved when entering a function, 12/'00, 0.3.7-11
unknown escape sequences are printed literally by echo, 03/'01, 0.3.7-15
"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.
"fnmatch" used again (and thus [^...]) 11/'01 with 0.3.80-30
"jobid" built-in removed, 02/'02 with 0.3.8-36
[Debian stable release 3.0 ("Woody") 07/'02 with 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 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.
"setvar" built-in removed 04/'03 with 0.4.14.
"fnmatch" not used anymore (and thus no [^...]) 04/'04 with 0.4.26
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.
"exp" aka "let" built-in removed 02/'05 with 0.5.3
[Debian stable release 4.0 ("Etch") 04/'09 with 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 0.5.4-12]
Slackware 8.1 (09/'06) then switched to a variant similar to dash 0.3.7-14.
It is based on a NetBSD ash tarball named 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
(until Slackware 13.1, at the time of this writing).
The debian changelog which is contained stops at 0.3.7-14, a fix from 0.3.7-11 is in
(preserve previous exit status upon entering a function), and a fix from 0.3.7-15 is not in
(unknown escape codes are printed literally by echo).
Some other smaller distributions, emphasizing on a slim shell, also use the Slackware shell variant.
Originally, the system shell on Android (/system/bin/sh) was an ash variant.
The Android core consists of a Linux kernel and, for license reasons, NetBSD utilities instead of GNU.
The initial release
(android-1.0) in the public part of the Android core source repository dates from
Oct 21 2007.
It's a checkout from the NetBSD repository, some time after 13th of june 2005
which is the latest rcs time stamp in the code.
NetBSD was going to be released as 3.0 soon, in December 2005.
The NetBSD ash source was checked out only once, early in the alpha phase of the Android project,
and was just minimally modified so that it compiled on Android.
From then on it was changed almost only for compiling reasons.
Android 2.3.1_r1: command line editing and history was added, using the
"linenoise" library, Dec 2010
Since Android 4, Oct 2011, (apparently rather some 3.x which is closed source though),
mksh is also available and has become the default shell for many apps, e.g. the terminal emulator.
The BusyBox distribution is aiming for small implementations.
Apart from that, emphasis is both on standards compliance and on user convenience,
where bash plays a role.
Although further features were added, there's no reference documentation
at the time of this writing (05/'11).
VMWare ESX (6.7.0) has it as system shell.
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").
The code was accumulated into one file and notably modified.
compile time options
to activate math, to deactivate jobcontrol and aliases,
to activate these built-ins:
type (early releases), getopts,
command, chdir, some flags for read (later releases);
and to integrate these commands as built-ins:
true+false (early releases),
echo, test (later releases)
ash became the default shell with busybox release 0.60.3 (04/'02).
compile time option ("ASH_BASH_COMPAT", active per default)
for several bash compatibility features:
option pipefail, substring and replacement parameter expansion
${x:y:z} and ${x/y/z},
[[, source, $'...', &>
undocumented: calls fnmatch(3) instead of the embedded pmatch(),
which has further issues due to bugs in some glibc versions.
This also introduces [^...] as synonym for [!...].
With Minix 2.0.3, an ash variant replaced the former "minix shell" as /bin/sh:
This ash was derived from 4.3BSD-Net/2, apparently with the
386bsd patchkit 2.4 applied.
Additionally:
knows tilde expansion
"-" is also end of options
"getopts" fixed ($OPTIND correct after an
"option requires an argument")
accepts empty command, e.g. "if ; [...]"
"false" built-in added (true was always a synonym for the colon command)
Minix specific:
Command line editing and history added by means of Minix readline()