Bash – Single or double brackets and portability

bashportabilityposixshell-scriptstandard

I have found some very good answers here on the differences between [ and [[ in 'if' statements. For specific named shells, it seems to be a good idea to use [[ over [ (and it is faster, too).

I'm still unclear on portability, however. If my goal is to write a script for POSIX compatible shells, scripts that I would begin with #!/bin/sh, how permissible is this syntax. From what I've read, double brackets are not in the POSIX standard, but in the "real world" how much of an issue is this really?

I suppose what I mean is that I want a portable script, but it is good enough for it to work on all viable POSIX shells post, say, 2000-2005. Meaning, it's not part of the standard, true, but realistically any shell from 2005 onward is almost certain to accept the syntax.

Also, a more general question concerning script portability and POSIX: how do other authors handle this? I understand use cases and target audience govern much of the decision, but do you try to stick as close to POSIX as possible to cut down on possible incompatibilities from the Internet at large, or do you avail yourself of all the nice things that most shells support that have yet to make it anywhere near a POSIX standard?

I began by trying to make most of my scripts as Bourne and POSIX compliant as possible. Over time, though, from reading more of the Bash documentation and from seeing other people's scripts on the Net, I have to say that making use of these other features can make for scripts that are much easier to read and in many cases much smaller.

Best Answer

If my goal is to write a script for POSIX compatible shells, scripts that I would begin with #!/bin/sh, how permissible is this [[ syntax.

Not at all. Many modern Linux-based systems use dash as /bin/sh by default, which is fully POSIX-compliant and no more, and so [[ will not work. This includes every recent Debian and Ubuntu release, and their derivatives, as well as many other distributions. Historically these systems commonly used Bash there instead, and deliberately switched to improve performance.

Many other systems, including most of the BSDs and most commercial Unices, don't support [[ either and never have: their sh is POSIX-only, or its extensions don't include the [[ syntax. OpenBSD's sh does support a version of [[, which is slightly different than Bash's; I don't know of any others that do, although they may exist. Otherwise, it's only systems that use Bash as /bin/sh (or less often zsh, or even less often some others) where [[ will work in something declared to be a sh script.


On the other hand, the large majority of systems have Bash installed in practice, and just making your script explicitly be run with bash will suffice for all of them. Bash's sh-emulation mode has always been broken anyway.

Since you're relying on Bash features, I can't see any reason at all you'd want to declare it as a sh script: just say #!/bin/bash and be done, using [[ as much as you want — or even better, to the total exclusion of [. If you instead want maximum portability, use [ or test and POSIX sh1, and write carefully.

1Note that some of the commercial Unices have, or have had, non-POSIX sh as /bin/sh; to work uniformly on those you'll need to run the scripts with the full path to the system's POSIX sh.