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?

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).

4
  • @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. Jan 3 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. Jan 3 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. Jan 3 at 13:38
  • Finish. Done. It is working. Thank you very much.
    – blueray
    Jan 3 at 13:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.