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?

Ahmad Ismail
  • 2,678

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

  • @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