[FFmpeg-devel] portable shell programming

Diego Biurrun diego
Sun Sep 27 16:06:34 CEST 2009


Since the topic cropped up after Stefano committed some bashisms, I
thought this might be helpful.

I recently wrote a quick guide to portable shell programming at work,
I'm pasting it here.  It's neither complete nor exhaustive, but it's a
start and it should help avoid the most glaring mistakes.  Further
comments and additions are welcome.


But first maybe I should explain what the point of this whole exercise
is.  Why bother fixing bashism when bash is ubiquitous free software?
It's true that bash is available everywhere and yes, it is the default
shell on most modern systems.  Or rather, it is the default
*interactive* shell on most modern systems.

bash has some drawbacks.  It is

- slow,
- bloated,
- has nonstandard syntax extensions.

Nowadays this tends to make people yawn and say that they don't care if
program XYZ uses up another 0.1% of their CPU cycles and/or another 0.1%
of their memory.

However, FFmpeg is expected to be portable and work on small embedded
systems.

Even for fullblown desktop machines performance is important.  Ubuntu
switched from bash to dash as /bin/sh (not default interactive shell)
and boot speed improved by around 30% IIRC.

Furthermore, nobody likes it when Microsoft bends and extends standards,
so you should not let the GNU people get away with it.

Notice that both Ubuntu and Debian use dash instead of bash nowadays.
I'm not sure about other environments, but there are more and the number
is increasing.

OK, now that you are convinced that writing portable shell scripts is
the way forward, here is how you go about it:


* default shell
  Make sure your system does not use bash as /bin/sh.


* correct shebang line
  Add a proper '#!/bin/sh' at the top of your shell scripts.  Don't use
  /bin/bash there.  Don't leave out the shebang line, behavior is
  non-deterministic without it.


* 'source' vs. '.'
  Use '.' instead of 'source' when including other files in your shell
  script.  'source' is bash-specific.


* 'let' and '(( ))'
  Both are bashisms.  Use arithmetic expansion with '$(( ))' instead.


* skip the 'function' keyword for function declarations
  Just use

    foo() { ....}

  instead of

    function foo() { ....}

  Bash understands both, POSIX only specifies the former, so use that.


* '==' in test invocations
  The builtin 'test' command in bash understands '==', but POSIX test
  does not and the builtin in other shells may or may not understand
  '=='.  Just use '=' instead.


* 'echo' with backslash escapes
  The builtin 'echo' in some shells does not support backslash escapes.
  Use '/bin/echo' or 'printf' instead if you absolutely need escape
  sequences.


* 'read' only works with a variable
  Write 'read line' instead of 'read', it's that simple.


* 'getopt' vs. 'getopts'
  The one with the 's' at the end is bash-specific, prefer the other.


* some parameter expansion expressions are non-portable
  An example is '${CMD:1}'.  There are more bash-specific ones that I
  don't remember offhand.  Use just the POSIX-compatible ones.  See
  http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02


* `` vs. $()
  Both are POSIX-compatible and backticks are even a tad more portable,
  but I wholeheartedly recommend the $() syntax.  Nesting backticks is
  possible, but will drive you crazy in a very short amount of time.


If you want to know if any bashisms crept into your script, try
'checkbashisms' from the Debian devscripts package.  It will check
your scripts for the most common bashisms.  But the most important
part is checking your scripts with dash or another POSIX-compatible
non-bash shell.

The POSIX specification is hosted at

http://www.opengroup.org/onlinepubs/009695399/

Refer to the "Shell & Utilities" section, also at

http://www.opengroup.org/onlinepubs/009695399/idx/xcu.html


That's it for now.  Further questions and feedback are welcome.

Diego



More information about the ffmpeg-devel mailing list