diff --git a/NEWS b/NEWS index 95d21edd4..53d727d43 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,14 @@ For full details, see the git log at: Any uppercase BUG_* names are modernish shell bug IDs. +2020-06-06: + +- The 'times' command is now a builtin command that conforms to POSIX + instead of an alias for the 'time' command. It displays the accumulated + user and system CPU times, one line with the times used by the shell and + another with those used by all of the shell's child processes. + https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_27 + 2020-06-05: - Fix a bug that caused special variables such as PATH, LANG, LC_ALL, diff --git a/src/cmd/ksh93/bltins/misc.c b/src/cmd/ksh93/bltins/misc.c index 8fe0b8853..bfd9188a3 100644 --- a/src/cmd/ksh93/bltins/misc.c +++ b/src/cmd/ksh93/bltins/misc.c @@ -36,6 +36,9 @@ * */ +#include +#include + #include "defs.h" #include "variables.h" #include "shnodes.h" @@ -461,6 +464,61 @@ int b_jobs(register int n,char *argv[],Shbltin_t *context) } #endif +/* + * times command + */ +int b_times(int argc, char *argv[], Shbltin_t *context) +{ + Shell_t *shp = context->shp; + const char *cmd = argv[0]; + struct tms cpu_times; + clock_t rv; + double utime, stime, utime_min, utime_sec, stime_min, stime_sec; + + while (argc = optget(argv, sh_opttimes)) switch (argc) + { + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg); + return(2); + default: + break; + } + if (error_info.errors) + errormsg(SH_DICT, ERROR_usage(2), "%s", optusage((char*)0)); + + argv += opt_info.index; + if (*argv) + errormsg(SH_DICT, ERROR_exit(3), e_badsyntax); + + rv = times(&cpu_times); + if (rv == (clock_t)-1) + errormsg(SH_DICT, ERROR_exit(2), "times(3) failed: errno %d: %s", + errno, strerror(errno)); + + /* First line: user and system times used by the shell */ + utime = (double)cpu_times.tms_utime / shp->gd->lim.clk_tck; + utime_min = floor(utime / 60); + utime_sec = utime - utime_min; + stime = (double)cpu_times.tms_stime / shp->gd->lim.clk_tck; + stime_min = floor(stime / 60); + stime_sec = stime - stime_min; + sfprintf(sfstdout, "%dm%.2fs %dm%.2fs\n", (int)utime_min, utime_sec, (int)stime_min, stime_sec); + + /* Second line: same for the shell's child processes */ + utime = (double)cpu_times.tms_cutime / shp->gd->lim.clk_tck; + utime_min = floor(utime / 60); + utime_sec = utime - utime_min; + stime = (double)cpu_times.tms_cstime / shp->gd->lim.clk_tck; + stime_min = floor(stime / 60); + stime_sec = stime - stime_min; + sfprintf(sfstdout, "%dm%.2fs %dm%.2fs\n", (int)utime_min, utime_sec, (int)stime_min, stime_sec); + + return(0); +} + #ifdef _cmd_universe /* * There are several universe styles that are masked by the getuniv(), diff --git a/src/cmd/ksh93/data/aliases.c b/src/cmd/ksh93/data/aliases.c index 8f3dc8510..fab6476dc 100644 --- a/src/cmd/ksh93/data/aliases.c +++ b/src/cmd/ksh93/data/aliases.c @@ -50,7 +50,6 @@ const struct shtable2 shtab_aliases[] = "stop", NV_NOFREE, "kill -s STOP", "suspend", NV_NOFREE, "kill -s STOP $$", #endif /*SIGTSTP */ - "times", NV_NOFREE, "{ { time;} 2>&1;}", "type", NV_NOFREE, "whence -v", "", 0, (char*)0 }; diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c index 36aca2aa7..a7b6d1f8a 100644 --- a/src/cmd/ksh93/data/builtins.c +++ b/src/cmd/ksh93/data/builtins.c @@ -115,6 +115,7 @@ const struct shtable3 shtab_builtins[] = "read", NV_BLTIN|BLT_ENV, bltin(read), "sleep", NV_BLTIN, bltin(sleep), "alarm", NV_BLTIN, bltin(alarm), + "times", NV_BLTIN|BLT_SPC, bltin(times), "ulimit", NV_BLTIN|BLT_ENV, bltin(ulimit), "umask", NV_BLTIN|BLT_ENV, bltin(umask), #ifdef _cmd_universe @@ -1761,6 +1762,15 @@ USAGE_LICENSE "[+SEE ALSO?\bulimit\b(2), \bgetrlimit\b(2)]" ; +const char sh_opttimes[] = +"[-1c?@(#)$Id: times (ksh community) 2020-06-06 $\n]" +"[+NAME?times - display CPU usage by the shell and child processes]" +"[+DESCRIPTION?\btimes\b displays the accumulated user and system CPU times, " +"one line with the times used by the shell and another with those used by " +"all of the shell's child processes. No options are supported.]" +"[+SEE ALSO?\btime\b(1)]" +; + const char sh_optumask[] = "[-1c?\n@(#)$Id: umask (AT&T Research) 1999-04-07 $\n]" USAGE_LICENSE diff --git a/src/cmd/ksh93/include/builtins.h b/src/cmd/ksh93/include/builtins.h index b9b4233d4..3759fcf09 100644 --- a/src/cmd/ksh93/include/builtins.h +++ b/src/cmd/ksh93/include/builtins.h @@ -105,6 +105,7 @@ extern int b_printf(int, char*[],Shbltin_t*); extern int b_pwd(int, char*[],Shbltin_t*); extern int b_sleep(int, char*[],Shbltin_t*); extern int b_test(int, char*[],Shbltin_t*); +extern int b_times(int, char*[],Shbltin_t*); #if !SHOPT_ECHOPRINT extern int B_echo(int, char*[],Shbltin_t*); #endif /* SHOPT_ECHOPRINT */ @@ -197,6 +198,7 @@ extern const char sh_optunset[]; #endif /* SHOPT_FS_3D */ extern const char sh_optwhence[]; #endif /* SYSDECLARE */ +extern const char sh_opttimes[]; extern const char e_dict[]; diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index b8faf4c5a..ab4e2f367 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -17,4 +17,4 @@ * David Korn * * * ***********************************************************************/ -#define SH_RELEASE "93u+m 2020-06-05" +#define SH_RELEASE "93u+m 2020-06-06" diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index 5f425c172..acb78fac3 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -820,8 +820,6 @@ but can be unset or redefined: .TP .B "suspend=\(fmkill \-s \s-1STOP\s+1 $$\(fm" .TP -.B "times=\(fm{ { time;} 2>&1;}\(fm" -.TP .B "type=\(fmwhence \-v\(fm" .PD .RE @@ -7112,6 +7110,11 @@ Suspends execution for the number of decimal seconds or fractions of a second given by .IR seconds . .TP +\f3times\fP +Displays the accumulated user and system CPU times, one line with the times +used by the shell and another with those used by all of the shell's child +processes. No options are supporetd. +.TP \(dg \f3trap\fP \*(OK \f3\-p\fP \*(CK \*(OK \f2action\^\fP \*(CK \*(OK \f2sig\^\fP \*(CK .\|.\|. The .B \-p diff --git a/src/cmd/ksh93/tests/builtins.sh b/src/cmd/ksh93/tests/builtins.sh index 683219c75..a8fe9dd66 100755 --- a/src/cmd/ksh93/tests/builtins.sh +++ b/src/cmd/ksh93/tests/builtins.sh @@ -665,8 +665,19 @@ actual=$( expect=$': print: I/O error\n1' if [[ $actual != *"$expect" ]] then - err_exit "I/O error not detected (expected '$expect', got '$actual')" + err_exit "I/O error not detected: expected $(printf %q "$expect"), got $(printf %q "$actual"))" fi +# ====== +# 'times' builtin + +expect=$'0m0.0[0-9]s 0m0.0[0-9]s\n0m0.00s 0m0.00s' +actual=$("$SHELL" -c times) +[[ $actual == $expect ]] || err_exit "times output: expected $(printf %q "$expect"), got $(printf %q "$actual"))" + +expect=$'*: times: incorrect syntax' +actual=$(set +x; eval 'times Extra Args' 2>&1) +[[ $actual == $expect ]] || err_exit "times with args: expected $(printf %q "$expect"), got $(printf %q "$actual"))" + # ====== exit $((Errors<125?Errors:125))