0
Declare total=O 
for repeat in {1..100}; do
   executiontime=$(gtime -f "%U" python3 main.py | tail -0)
   total=$(echo "scale=2; $total + $executiontime" | bc)  
done
echo "$total/100"

The code above is a part of a loop, and I need the variable total to be able to have the average of execution time of the file main.py. I am having a hard time getting to print the value of the variable total since it is a floating point variable. What is the correct syntax to do this?

This is the output I am getting:

 (standard_in) 2: parse error

I think the issue is within the command tail when I use : gtime -f "%U" python3 main.py | tail -1 this is the output I get:

  $ ./gtime -f "%U" python3 main.py | tail -1 
    10.08
    )

but then with tail -0

gtime -f "%U" python3 main.py | tail -0
9.66
basel117
  • 189
  • 1
  • 10
  • Do `total` and `executiontime` both have non-empty values? The error you are seeing comes from `bc`, not the shell. – chepner Apr 11 '19 at 13:19
  • 1
    `tail -0`, in particular, shouldn't output *anything*. – chepner Apr 11 '19 at 13:19
  • @chepner for my code it does though, it gives a number and then it skips a line, like \n or something. I am also confused – basel117 Apr 11 '19 at 13:24
  • What's the output when you run it with `tail -0`? I'm with @chepner here, it should NOT output anything as you're instructing `tail` to only output the last 0 lines. – tobias Apr 11 '19 at 13:29
  • But did you confirm that `executiontime` actually has a non-empty value? I don't know what `gtime` is or what your `main.py` outputs, but `gtime` may be writing to standard error. – chepner Apr 11 '19 at 13:29
  • I can produce that exact error with `echo "scale=2; 3+" | bc`, which is what you would get with `total=3` and `executiontime=`. – chepner Apr 11 '19 at 13:31
  • Your update confirms that you want to capture standard *error*, not standard *output*. See my answer. – chepner Apr 11 '19 at 13:36
  • @tobias I edited the question, **tail -0** does give me the last line's content. **tail -1** give me the last 2 lines. I guess the index 0 for **tail** in the last line and then counts up, which is why it is giving me a value. – basel117 Apr 11 '19 at 13:36
  • The number is coming from standard error, and is not affected by the pipe to `tail`. `tail -1` is outputting *only* the `)`. – chepner Apr 11 '19 at 13:37

2 Answers2

2

gtime writes the time to standard error, which is what you want to capture, not standard output. Use this:

executiontime=$(gtime -f "%U" python3 main.py 2>&1 >/dev/null)

The 2>&1 duplicates standard error onto gtime's standard output; >/dev/null causes gtime's standard output to be discarded. The end result is that you capture the time output by gtime, but none of main.py's output.

Piping to tail -0 is basically an expensive equivalent of > /dev/null, but standard error is not written to the pipe, which is why you still see the number. But $(...) isn't capturing that.

chepner
  • 497,756
  • 71
  • 530
  • 681
1

First, you need to ensure that executionTime holds the floating point number that you expect, then you can proceed to calculate the average execution time.

The answer will be different depending on the shell you use. Bash for example does not support floating point arithmetic, hence, this would not work:

# will output the plain string without performing any arithmetic
echo "$total/100" 

Instead, you will need to use an alternative approach, such as:

echo $(bc <<< "scale=2; $total/100")

Allow me to link a few related answers that explain other methods:

How do I use floating-point division in bash?

How can I do division with variables in a Linux shell?

tobias
  • 934
  • 8
  • 17
  • still not working, with same error in output. I think the **tail -0** gives a different output than what it supposed to be (a float number). – basel117 Apr 11 '19 at 13:21
  • What shell are you using? And what's the output of the variables `executiontime` and `total`? – tobias Apr 11 '19 at 13:31