January 30, 2013

A bashism a week: sleep

To delay execution of some commands in a shell script, the sleep command comes handy.
Even though many shells do not provide it as a built-in and the GNU sleep command is used, there are a couple of things to note:

  • Suffixes may not be supported. E.g. 1d (1 day), 2m (2 minutes), 3s (3 seconds), 4h (4 hours).
  • Fractions of units (seconds, by default) may not be supported. E.g. sleeping for 1.5 seconds may not work under all implementations.

This of course is regarding what is required by POSIX:2001; it only requires the sleep command to take an unsigned integer. FreeBSD's sleep command does accept fractions of seconds, for example.

Remember, if you rely on any non-standard behaviour or feature make sure you document it and, if feasible, check for it at run-time.

In this case, since the sleep command is not required to be a built-in, it does not matter what shell you specify in your script's shebang. Moreover, calling /bin/sleep doesn't guarantee you anything. The exception is if you specify a shell that has its own sleep built-in, then you could probably rely on it.

The easiest replacement for suffixes is calculating the desired amount of time in seconds. As for the second case, you may want to reconsider your use of a shell script.

1 comment:

  1. Using #!/bin/mksh or #!/bin/mksh-static (on Debian) does actually provide a sleep builtin that can handle fractions (up to microseconds) but no sufficēs.

    /usr/share/doc/mksh/examples/uhr.gz contains a script that uses this to sleep until the start of the next full second, by using the (also mksh- and zsh-specific) $EPOCHREALTIME variable. (Note that fractional parts here are dependent on gettimeofday() support by the OS.)

    In #!/bin/sh scripts in Debian, you might be able to rely on calling /bin/sleep for extra features, but not in portable POSIX sh scripts.

    That being said, I think that (Korn) Shell is an okay implementation language, although if you’re restricted to #!/bin/sh it’s only good for very basic tasks, as you often need to fork-and-exec things like sed(1). But this series is about “bashisms” (there’s actually such thing as a “dashism” too, see LP#575154 for an example) which, per definitionem, can only occur in #!/bin/sh scripts (as opposed to #!/bin/bash scripts). Most of my mksh scripts/programs don’t call an external utility at all, or don’t do that often, which is pretty decent (still not as fast as a compiled C program of course), and I think one should not condemn shell scripting and shell programming generally. It’s just the inexperienced need some amount of education; https://evolvis.org/projects/shellsnippets/ contains some examples for those who’d like to learn by reading other peoples’ code (additions welcome, subject to the charter of that project, being, bourne/posix/korn/z shell code of decent quality and free licence).

    Thanks Raphaël for taking the step to educate such people about bashisms and doing the effort of writing lengthy blogpostings every week to that effect!