0

The result of BASH time (run 5 times) is stored in a text file as decimal. I then read back in the values and compute the average using bc. Finally, I output the resulting average as a decimal to a file. My script seems to work, (no errors in Mate Terminal on Linux Mint, both .txt files are created) except the final output to file is "0".

TIMEFORMAT=%R
tsum=0

for i in {1..5}
do
(time sh -c \
'openssl des3 -e -nosalt -k 0123456789012345 -in orig.jpg -out encr.enc; '\
'openssl des3 -d -nosalt -k 0123456789012345 -in encr.enc -out decr.dec'\
) 2>&1 | grep 0 >> outtime.txt
done

avgDES3=0
cat outtime.txt | \
while read num
do
tsum=`echo $tsum + $num | bc -l`
done

avgDES3=`echo "$tsum / 5" | bc -l`
echo "DES3 average is: " $avgDES3 >> results.txt

I've also tried replacing the last line with: printf "DESCBC average is: " $avgDESCBC >> results.txt

the outtime.txt is:

0.220
0.218
0.226
0.223
0.217

and results.txt is:

DES3 average is:  0

I'd appreciate help getting the resulting average to be a decimal. Perhaps I'm not using the correct value of the tsum variable in the next to last line (eg. if tsum global isn't changed by the expression within the loop)?

EDIT: Issue (as pointed out by rbong and Arun) was piping to a subshell (global variable not changed after loop expression). Origninally script was producing appropriate outtime.txt on my system (no errors, just didn't get tsum value from loop).

morse
  • 3
  • 3
  • 3
    http://mywiki.wooledge.org/BashFAQ/024 – Etan Reisner Nov 24 '14 at 20:46
  • what outtime.txt and outputtime.txt? – AKS Nov 24 '14 at 21:00
  • the reason for that is.. your for loop is NOT capturing the output of "time" command ... and putting it in output.txt. And you are reading output.txt to create results.txt and which might be doing some strange calculations as time's output never went to outtime.txt which you use to get tsum value for each run of "for" loop and calculating avgDES3 variable. echo $tsum and see what you are getting in it first. – AKS Nov 24 '14 at 21:03
  • possible duplicate of [Bash variable scope](http://stackoverflow.com/questions/124167/bash-variable-scope) – Josh Jolly Nov 24 '14 at 21:21
  • @ArunSangal Why do you say the OP isn't writing to `outtime.txt`? The `outputtime.txt` label is fairly clearly a typo in the prose of the question. – Etan Reisner Nov 24 '14 at 21:39
  • because, i thought he might be using two diff files. outtime.txt does not JUST contain just 0.023 or x.yyx kind of lines in it. It's the whole output of this commands which he's passing to sh -c command. Now.. that you clarified.. his code can be fixed if he can try my answer. I though for reading line from while loop, he should read it from outputtime.txt which had just x.xxx y.yyy enteries per line. – AKS Nov 24 '14 at 21:44
  • @EtanReisner actually if you run his code on your machine, you'll notice that outtime.txt is not exactly what he SHOULD use for reading "num" variable and calculating average variable avgDES3. outime.txt from his code has the whole output of all commands he's passing to sh -c session and his code is not even capturing "time" output which is the ONLY thing he needs to calculate average variable $avgDES3. That's why I asked him if outtime.txt and outputtime.txt are 2 different files. http://stackoverflow.com/questions/13356628/is-there-a-way-to-redirect-time-output-to-file-in-linux – AKS Nov 24 '14 at 22:09
  • Sorry about typos - fixed now. Original script was working well on my system (no content errors in .txt files). Mate on Mint. – morse Nov 25 '14 at 01:52

2 Answers2

1

Executing your script with the bash -x option for debugging reveals that the tsum variable is acting as expected in your while loop, then its value is reset to zero after the loop exits.

This happens because you are creating a new subprocess when you use the | operator just before while, and the subprocess has its own copy of the variable. You can avoid this by not piping the output from cat into a loop, but instead using a redirect operator to achieve the same result without creating a subprocess.

This is done by changing this

cat outtime.txt | \
while read num
do
tsum=`echo $tsum + $num | bc -l`
done

to this

while read num
do
    tsum=`echo $tsum + $num | bc -l`
done < outtime.txt

With this simple change, your new output becomes

DES3 average is:  .22080000000000000000

To learn more, read here.

http://www.gnu.org/software/bash/manual/html_node/Redirections.html

rbong
  • 86
  • 7
  • I agree with rbong on while loop and cat file with "|". But, the solution in his for loop is not generic i.e. outtime.txt file contains output of whatever command he's passing to sh -c session. Can you share, using his code and your code change, what's the output of outtime.txt file? – AKS Nov 24 '14 at 22:22
  • With his code and your suggested code change, I see the followig lines in outtime.txt.. 0.113 0.109 0.109 0.111 0.110 5427:error:02001002:system library:fopen:No such file or directory:bss_file.c:352:fopen('orig.jpg','r') lib:bss_file.c:354: 0.008 5438:error:02001002:system library:fopen:No such file or directory:bss_file.c:352:fopen('encr.enc','r') 5438:error:20074002:BIO routines:FILE_CTRL:system ..... something like that.. which is not a value input for "while" loop for reading num variable. – AKS Nov 24 '14 at 22:29
  • @ArunSangal My changes have nothing to do with this. That output is produced by the for loop at the beginning of the file. I get similar errors. If you manually populate outtime.txt with the output the original post claims to be getting and remove the for loop then try both the original and my changes, you will see the expected behaviour. I'm not sure what causes these errors, but the question was about the variable being set to zero. – rbong Nov 24 '14 at 22:42
  • Then, your comment on while and | was "to the point" answer but I thought there were 2 issues, one with creation of outtime.txt and 2nd with while and | use creating a subshell and the reason for tsum variable to loose its scope. – AKS Nov 24 '14 at 22:44
  • OP claims to be getting clean output if you look at his dump of outtime.txt. I can assume that he has not posted the most recent code or he does not get the error on his system. Either way, he is aware of the error now and can address the issue or even post a more appropriate question. – rbong Nov 24 '14 at 22:51
0

Try this script. Using { , } around time command you can capture the OUTPUT of "time" command and use "2" identifier for creating outtime.txt file in append mode. Before starting the script, this file should be created fresh OR you can comment the ">outtime.txt" line. A ';' character just before closing '}' brace is important OR it won't end the begining '{'. This will FIX your outtime.txt file contents/data issue.

Other issue is with while loop as you are using "|" before while loop and due to that a new subshell is getting created for while loop and tsum variable is loosing its value when it's out of the while loop. Feed while loop "outtime.txt" file like shown below in my reply.

#!/bin/bash

TIMEFORMAT=%R
tsum=0

#create fresh outtime.txt and results.txt files
>outtime.txt

#if you want this file to be appended for future runs, comment the following line.
>results.txt

for i in {1..5}
do
{ time sh -c \
'openssl des3 -e -nosalt -k 0123456789012345 -in orig.jpg -out encr.enc; '\
'openssl des3 -d -nosalt -k 0123456789012345 -in encr.enc -out decr.dec'\
} 1>/dev/null 2>&1; } 2>> outtime.txt
done
## Now at this point, outtime.txt will contain only x.xxx time entries per line for 5 runs of "for" loop.
echo File outtime.txt looks like:
echo ----------
cat outtime.txt
echo;
## Now lets calculate average.
avgDES3=0
while read num
do
tsum=`echo $tsum + $num | bc -l`
done < outtime.txt; ## Feed while loop this outtime.txt file


avgDES3=`echo "$tsum / 5" | bc -l`
echo "DES3 average is: " $avgDES3 > results.txt
## Logically you should usr a single > re-director for results file. Instead of >> which is used for appending to file while creating results.txt.

#Show the output/average
echo; echo File results.txt looks like:
cat results.txt

OUTPUT:

File outtime.txt looks like:
----------
0.112
0.108
0.095
0.084
0.110


File results.txt looks like:
DES3 average is:  .10180000000000000000
AKS
  • 16,482
  • 43
  • 166
  • 258