On Wed, Nov 01, 2017 at 01:19:08PM -0700, Alan Dipert wrote: [...] > I can imagine many reasons not to add a new variable, including the fact > that it could change the behavior of existing scripts. It may also be the > case that there’s already a method to get sub-second times without shelling > out, and so I’d be grateful for pointers to any existing solutions. [...]
Probably the easiest option is to implement this as a loadable builtin: $ src=~/src/gnu; gcc -fPIC -g -O0 -I $src/bash/ -I $src/bash/include -I $src/build-bash-devel/ -I $src/bash/examples/loadables/ -I $src/bash/builtins/ -c -o timer.o timer.c $ gcc -shared -Wl,-soname,timer -o timer timer.o $ enable -f ./timer timer $ timer current delta $ echo $current, $delta 1509589044.350954, 0.0 $ timer current delta $ echo $current, $delta 1509589059.42946, 14.691992 $ timer current delta; sleep 3.14; timer current delta; echo $delta 3.143473 Given this, I don't see a reason to add this functionality to bash itself. Below is the (buggy and ugly) implementation of the `timer' loadable builtin: --- #include <config.h> #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include "loadables.h" /* FIXME: do better validation */ static int parse_timeval (const char *s, struct timeval *tv) { char *ds; timerclear(tv); tv->tv_sec = strtol(s, &ds, 10); if (ds && *ds == '.') { tv->tv_usec = strtol(ds + 1, NULL, 10); } return 0; } int timer_builtin (WORD_LIST *list) { struct timeval tv1, tv2, tv3; char *s, *current, *delta; char b1[64], b2[64]; /* FIXME */ if (0 == list) { return (EXECUTION_FAILURE); } current = list->word->word; if (0 == current || 0 == *current) { return (EXECUTION_FAILURE); } if (0 == list->next) { return (EXECUTION_FAILURE); } delta = list->next->word->word; if (0 == delta || 0 == *delta) { return (EXECUTION_FAILURE); } if (-1 == gettimeofday(&tv1, NULL)) { return (EXECUTION_FAILURE); } s = get_string_value (current); if (0 == s) { bind_variable (delta, "0.0", 0); goto update_value; } parse_timeval (s, &tv2); timersub (&tv1, &tv2, &tv3); snprintf (b2, 64, "%ld.%ld", tv3.tv_sec, tv3.tv_usec); bind_variable (delta, b2, 0); update_value: snprintf (b1, 64, "%ld.%ld", tv1.tv_sec, tv1.tv_usec); bind_variable (current, b1, 0); return (EXECUTION_SUCCESS); } char *timer_doc[] = { "...", "", "...", (char *)NULL }; struct builtin timer_struct = { "timer", timer_builtin, BUILTIN_ENABLED, timer_doc, "timer CURRENT DELTA", 0 };