3

Short question:

This is done on a Mac:

time for i in {1..10}; do python3 foo.py ; done

but CTRL-C won't be able to stop it. How to make it work? (or how to time the running time of N times?)


Details:

There is some standard test of program from github, and I could run it:

 python3 foo.py

or

 time python3 foo.py

and it reports 0.27 seconds running time. Since the test is wired up for 1000 test cases and to a test framework, I don't want to change the test, so I want to time it 100 times. It seems the command time has no way to time it for 10 or 100 times (this is somewhat strange of Unix that so many years and something this useful and simple is not built into time). The following can be used:

time for i in {1..10}; do python3 foo.py ; done

but CTRL-C won't be able to stop it -- it will stop that one python script and keep on running the rest. So fortunately it wasn't 100 or 1000 that was typed in. Is there a way to use time or a better way to do it? (besides changing the program?)

nonopolarity
  • 3,069
  • You can use Ctrl+Z. After that the shell quits the loop and you would have the same effect. – lainatnavi Mar 08 '20 at 22:21
  • I am surprised it has to be the CTRL-Z trick... I just tried creating a try.sh with `#!/bin/sh

    time for i in {1..10}; do python3 foo.py ; done` and CTRL-C also doesn't work... doesn't a shell actually have something that is: when the shell script gets the CTRL-C, then stop it altogether?

    – nonopolarity Mar 09 '20 at 00:22
  • You could add a signal handler to the python script and then launch it with || break. – Alexander Mar 09 '20 at 07:06

3 Answers3

1

It's not "Ctrl+C" solution but something if you want to stop "gracefully" long loop sequence. All you need to do is create ./stop-foo-py file; with $ echo "" > ./stop-foo-py for example (in another terminal).

rm ./stop-foo-py
time for ((i=0;i<1000;i++));
    do if [ ! -f "./stop-foo-py" ]; then
        python foo.py ;
        fi ;
    done

or rm ./stop-foo-py; time for ((i=0;i<1000;i++)); do if [ ! -f "./stop-foo-py" ]; then python foo.py ; fi ; done in one line.

It adds about half of ms per single loop.

$ time for ((i=0;i<1000;i++)); do if [ ! -f "./stop" ]; then : ; fi ; done

real    0m0.548s
user    0m0.157s
sys     0m0.359s
tansy
  • 741
1

It's not possible with Ctrl-C since you are generating new processes in a loop. You would have to interrupt all of them by pressing Ctrl-C 100, 1000 times as fast as each iteration is executing.
As an alternative you could achieve the same effect in bash by pressing Ctrl-Z which would stop the latest foreground process created by the loop and quit the loop itself.

1

Assuming the shell is zsh, just do:

time (repeat 10 python3 foo.py)

That times the process (and waited for children) that runs the subshell that runs the python3 command 10 times.

With bash or ksh93 (or zsh), you can do:

time (for ((i=0;i<10;i++)) { python3 foo.py; })

POSIXly, you could do:

time -p sh -c '
  i=0; while [ "$i" -lt 10 ]; do
    python3 foo.py
    i=$((i + 1))
  done'
  • interesting... zsh actually lets you press CTRL-C to stop everything. Wikipedia: "macOS Catalina, released in October 2019, adopted Zsh as the default shell, replacing Bash." – nonopolarity Mar 09 '20 at 07:21