Is there a minimally POSIX.2 compliant shell (let's call it mpcsh
) in the following sense:
if mpcsh myscript.sh
behaves correctly on my (compliant) system then xsh myscript.sh
will behave identically for any POSIX.2 compliant shell xsh
on any compliant system. ("Identically" up to less relevant things like the wording of error messages etc.)
Does dash qualify?
If not, is there any way to verify compliance of myscript.sh
?
Edit (9 years later):
The accepted answer still stands, but have a look at this blog post and the chackbashisms
command (source). Avoiding bashisms is not the same as writing a POSIX.2 compliant shell script, but it comes close.
Since POSIX is a specification, there is no shell called POSIX shell. You can use POSIX standard in many shells such as, dash , bash , ksh , mksh , yash , zsh , etc. You need to be aware that each shell has its own commands and options or different options top of the POSIX specification.
fish, the friendly interactive shell, is a commandline shell intended to be interactive and user-friendly. fish is intentionally not fully POSIX compliant, it aims at addressing POSIX inconsistencies (as perceived by the creators) with a simplified or a different syntax.
BusyBox is a software suite that provides several Unix utilities in a single executable file. It runs in a variety of POSIX environments such as Linux, Android, and FreeBSD, although many of the tools it provides are designed to work with interfaces provided by the Linux kernel.
POSIX Shell is a command line shell for computer operating system which was introduced by IEEE Computer Society. POSIX stands for Portable Operating System Interface. POSIX Shell is based on the standard defined in Portable Operating System Interface (POSIX) – IEEE P1003. 2.
It won't help you (not as much and reliably as you would expect and want it to anyway).
Here is why.
One big problem that cannot be addressed by a virtual "POSIX shell" are things that are ambiguously worded or just not addressed in the standard, so that shells may implement things in different ways while still adhering to the standard.
Take these two examples regarding pipelines, the first of which is well known:
$ ksh -c 'printf "foo" | read s; echo "[${s}]"' [foo] $ bash -c 'printf "foo" | read s; echo "[${s}]"' []
ksh
executes the last command of a pipe in the current shell, whereas bash
executes all - including the last command - in a subshell. bash 4
introduced the lastpipe
option which makes it behave like ksh
:
$ bash -c 'shopt -s lastpipe; printf "foo" | read s; echo "[${s}]"' [foo]
All of this is (debatably) according to the standard:
Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment.
I am not 100% certain on what they meant with extension, but based on other examples in the document it does not mean that the shell has to provide a way to switch between behavior but simply that it may, if it wishes so, implement things in this "extended way". Other people read this differently and argue about the ksh
behavior being non-standards-compliant and I can see why. Not only is the wording unlucky, it is not a good idea to allow this in the first place.
In practice it doesn't really matter which behavior is correct since those are the """two big shells""" and people would think that if you don't use their extensions and only supposedly POSIX-compliant code that it will work in either, but the truth is that if you rely on one or the other behavior mentioned above your script can break in horrible ways.
This one I learnt about just a couple of days ago, see my answer here:
foo | bar 2>./qux | quux
Common sense and POLA tells me that when the next line of code is hit, both quux
and bar
should have finished running, meaning that the file ./qux
is fully populated. Right? No.
POSIX states that
If the pipeline is not in the background (see Asynchronous Lists), the shell shall wait for the last command specified in the pipeline to complete, and may also wait for all commands to complete.)
May (!) wait for all commands to complete! WTH!
bash waits:
The shell waits for all commands in the pipeline to terminate before returning a value.
but ksh doesn't:
Each command, except possibly the last, is run as a separate process; the shell waits for the last command to terminate.
So if you use redirection inbetween a pipe, make sure you know what you are doing since this is treated differently and can horribly break on edge cases, depending on your code.
I could give another example not related to pipelines, but I hope these two suffice.
Having a standard is good, continuously revising it is even better and adhering to it is great. But if the standard fails due to ambiguity or permissiveness things can still unexpectedly break practically rendering the usefulness of the standard void.
What this means in practice is that on top of writing "POSIX-compliant" code you still need to think and know what you are doing to prevent certain things from happening.
All that being said, one shell which has not yet been mentioned is posh
which is supposedly POSIX plus even fewer extensions than dash
has, (primarily echo -n
and the local
keyword) according to its manpage:
BUGS Any bugs in posh should be reported via the Debian BTS. Legitimate bugs are inconsistencies between manpage and behavior, and inconsistencies between behavior and Debian policy (currently SUSv3 compliance with the following exceptions: echo -n, binary -a and -o to test, local scoping).
YMMV.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With