February 27th 2018
A few years ago I noticed that sleep is not built into bash and instead calls an external command each time.
I like to make my scripts responsive and unobtrusive by relying on bash builtins as much as possible; my reasoning: I am using one of the heaviest shells with all its bells and whistles, so at least use it as fully as possible. Once the shell has fired up, a multiline string manipulation should still be much faster than a single call to grep or sed etc., and without reading from the hard drive.
My hard drives are the oldest and slowest parts inside my computer...
bash has a mechanism to load builtins from a "shared object", usually a file in /usr/lib*/bash/. See help enable.
Make it portable:
#!/bin/bash for file in /usr/lib/bash/sleep /usr/lib32/bash/sleep /usr/lib64/bash/sleep; do [ -r "$file" ] && enable -f "$file" sleep && break done # Portable enough? # a little test: delay=0.01 # 100 times per second I=6000 # should amount to 1 minute printf "Time for builtin loaded from $file:" time ( for ((i=0 ; i<I; i++)); do sleep $delay; done ) enable -d sleep printf "Time without builtin:" time ( for ((i=0 ; i<I; i++)); do sleep $delay; done )
The time difference:
Time for builtin loaded from /usr/lib/bash/sleep: real 1m0.899s user 0m0.300s sys 0m0.093s Time without builtin: real 1m14.334s user 0m9.227s sys 0m5.502s
Please keep in mind that bash builtins might have different functionality than the equivalent external utilities. In the case of sleep, the builtin is able to take fractions (just like the external), but always assumes seconds.
Here's a list of all builtins that come with my version of bash (4.4.19):
$ ls /usr/lib/bash/ Makefile.inc finfo ln mypid printenv rmdir strftime truefalse unlink basename head logname pathchk push setpgid sync tty whoami dirname id mkdir print realpath sleep tee uname