3

I am using How to define and load your own shell function in zsh to convert my zsh script to shell function.

The script I am trying to convert is:

#! /bin/zsh -

trap true INT QUIT

zmodload zsh/datetime
TIMEFMT='Total duration: %*E'
strftime -s start 'Start Time: %d/%m/%y %I:%M%P'
{
  duration=$(
    exec 4>&2 2>&1 1>&3 3>&-
    time "$@" 2>&4 4>&-
  )
} 3>&1
ret=$?
strftime -s end 'End Time: %d/%m/%y %I:%M%P'
echo -e
print -rlu2 $start $end $duration
return $ret

So, I removed the shebang and placed the script in my fpath.

The problem is, it is no more showing the $duration:

% reporttime tail -f ~/.xsession-errors
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
^C
Start Time: 03/01/21 03:15pm
End Time: 03/01/21 03:15pm

What can i do?

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
Ahmad Ismail
  • 2,478
  • 1
  • 22
  • 47

1 Answers1

2

I can't reproduce your problem. But if you want to make that an autoloadable function, you'd want to make the traps and variables local to the function. The output of echo -e should also go to stderr like the rest of the report, or add that extra newline in the call to print:

zmodload zsh/datetime

set -o localtraps
trap true INT QUIT

local TIMEFMT='Total duration: %*E' start end ret duration

strftime -s start 'Start Time: %d/%m/%y %I:%M%P'

{
  duration=$(
    exec 4>&2 2>&1 1>&3 3>&-
    time "$@" 2>&4 4>&-
  )
} 3>&1
ret=$?

strftime -s end 'End Time: %d/%m/%y %I:%M%P'
print -rlu2 '' $start $end $duration
return $ret

Another option would be to enclose the whole thing in (...) so it is run in a subshell.

Note that as already mentioned in the answer you're referring to, since zsh's time reports resources consumed by a process (which in zsh is not limited to elapsed and cpu time, but can include memory usage, context switches, I/O operations...), it can only be used for commands that are being run in a child process. So if you want to be able to time a function for instance, you'd need to replace time "$@" with time ("$@") so the function is run in a subshell process.

But as you're only interested in the elapsed time, and not really process resources, you might as well use the other approach I suggest there, and just do the end-start time calculation by hand (and do the HH:MM:SS.TTT formatting by hand or using strftime if you like).

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • @blueray, it's working for be with `autoload reporttime` and `reporttime sleep 1` or `reporttime trail -f /etc/issue` interrupted with `^C` with zsh 5.8. In which way is it not working for you? With what version of `zsh`? For `(...)`, take the original script, add a `(` line at the top and a `)` line at the bottom. – Stéphane Chazelas Jan 03 '21 at 13:28
  • In which way is it *not working*? The `(...)` was so that you can use the original script (the one that ends with `exit`) asis without worrying about scope as a subshell runs in separate, child process in `zsh`. `print -l` prints its arguments one per line. See how I've added a `''` here to first print an empty line. – Stéphane Chazelas Jan 03 '21 at 13:34
  • @blueray, is it possible that you're testing it with a command that is actually a function? functions can't be timed in `zsh` as `zsh`'s `time` reports resources used by a *process* once that process terminates. To report resources of a process that runs a `zsh` function, you'd need to `time` a subshell that runs that function. Here, you could replace `time "$@"` with `time ("$@")` for that. Or you can use the approach using `$epochtime` in my other answer. – Stéphane Chazelas Jan 03 '21 at 13:38
  • Finish. Done. It is working. Thank you very much. – Ahmad Ismail Jan 03 '21 at 13:40