The Mysterious KSH93 Alarm Built-in

Sometimes it is useful to have part of a shell script run periodically, e.g. once a millisecond or every 10 minutes.  Although this is possible by starting a process in the background, ksh93 has an easier (but undocumented) feature which allow a script writer to set up interval timers.  This undocumented feature is a built-in called alarm and a corresponding discipline also called alarm. I am not going to attempt to explain what a discipline or a compund variable is in this post as I assume that you have read the ksh93 man page.  If you list your built-ins using the builtin command, you will see the alarm built-in listed along with the other built-ins.  According to Dave Korn, ksh93 has the ability to handle multiple timeout events using alarm but this feature remains undocumented since "I have not decided what interface I want for this functionality."

If you try to retrieve information about alarm, using the standard ksh93 builtin options (--man or --help) only a single usage line is outputted.
$ alarm --man
Usage: alarm [-r] [varname interval]
$
Dave Korn has stated that -r means repeat the alarm every interval, varname is the name of the variable which is invoked, and interval can be the absolute time from the Epoch or of the form +nseconds.   Milliseconds are also supposedly supported but I have not tested this functionality.

Internally, alarm is an ksh93 built-in which adds an alarm discipline to a function or variable. This built-in sets up an interval timer that will call the alarm discipline as needed.

For our first example, consider the following trivial example which uses alarm to display the time every 2 seconds
alarm -r mytime +2
function mytime.alarm { print -n "$(date +%H:%S)\r"; }
read dummy # dummy wait
The first line specifies that the function mytime is to be called every 2 seconds.  The second line defines the mytime function i.e. print the current time in HH:SS format.  The third line is just a hack so that you can see the results of the previous 2 lines.

Note that ksh93 is very picky as regards how statements are written when discipline functions are used.  For example, if you place the mytime function definition before the alarm statement, ksh93 will produce an error, i.e. "mytime.alarm: invalid discipline function" and exit the script.

Next is an example that demonstrates how to abort a script after a waiting 10 seconds for input from a user.  Note that the ksh93 read command has a timeout option but we are not using it here.  This example also shows you how to remove an alarm using the unset built-in.
alarm -r abortscript +10

abortscript.alarm()
{
print "Exceeded allowed time. Aborting script ......"
kill -9 $$
}

print "waiting for input from read"
read dummy # dummy wait - press return to continue

unset abortscript
print "abortscript unset. Press return to exit"

read dummy # dummy wait - press return to continue

exit 0
Here is the output when this example is run.
$ ./example2
waiting for input from read
Exceeded allowed time. Aborting script ......
Killed
$
$ ./example2
waiting for input from read

abortscript unset. Press return to exit

$
My final example shows how alarm can be used to update a progress bar once a second on a terminal.
alarm -r progressbar +1

progressbar.alarm()
{
tput cup 2 10
(( ++progressbar.pvalue > 50 )) && {
tput cup 2 10; tput el
progressbar.pvalue=0
}
printf "Progress: %s" "${progressbar.pstr:1:${progressbar.pvalue}}"
}

progressbar.pvalue=0
progressbar.pstr="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

tput clear
read dummy?"Press RETURN to exit"

unset progressbar

exit 0
Again the order of things in the script is very important.  First we specify the function that alarm is going to use, next we define the function itself and then we set the compound variable values.

Use alarm with caution since Dave Korn has also stated that "alarm hasn't been documented because it is not working in all cases."  The examples shown in this post were tested using ksh93 version s.

0 comments:

Post a Comment