-3

I have a txt file with integers on each line and i want the sum.

SUM=0                             

while read line || [ -n "$line" ] ; do
    let "SUM += line"             

done                                  
echo $SUM                         

The problem is that while most of the time I get the correct result, sometimes I get SUM+1.

How can this be explained?

Input file:

2 
38
21
50
42
59
19
19
29
17
24
13
45
49
48
13
20
20
51
41
51
45
1 
17
6 
46
52
50
32
19
8 
28
35
33
13
4 
2 
49
32
19
17
17
16
51
23
32
26
54
31
54
14
17
55
53
18
34
4 
16
15

Expected sum: 1709, sometimes I get 1710.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
BragiPls
  • 17
  • 1
  • 4
  • 1
    Better to use: `awk '{sum+=$1} END{print sum}' file` – anubhava Jul 20 '18 at 15:34
  • As for better ways of doing what you're doing, have a look at [this question](https://stackoverflow.com/questions/450799/shell-command-to-sum-integers-one-per-line). Your question isn't 'a duplicate, though, as you're not asking how to do it, but why you're seeing the `+1` you describe. – Benjamin W. Jul 20 '18 at 15:37
  • Logging would go a long way towards figuring out the issue. If you run `bash -x yourscript` to print each line as it's executed, and compare the logs from a working instance to a broken instance, you'll have your answer. (BTW, `let` is obsolete; `(( SUM += line ))` is the modern alternative). Put `: SUM="$sum" line="$line"` inside the loop to make your `set -x` logs contain the current values. – Charles Duffy Jul 20 '18 at 15:47
  • See https://ideone.com/mQv4zg for an online interpreter running your code 1000 times, and getting the same answer on all of them. If you can fork the code there so it returns inconsistent results, *then* we'd have a problem we can reproduce, and thus start to answer. – Charles Duffy Jul 20 '18 at 15:52
  • Shouldn't `||` be `&&`? – Barmar Jul 20 '18 at 16:08
  • @Barmar No, that's for the case where your file doesn't have a proper EOL marker on its last line, see [BashFAQ](https://mywiki.wooledge.org/BashFAQ/001#My_text_files_are_broken.21__They_lack_their_final_newlines.21). – Benjamin W. Jul 20 '18 at 17:01
  • @CharlesDuffy When i reproduce the code you supplied in ideone, i have only good outputs. But when i move the function runOnce() into a standalone script, i start to have that kind of outputs declare -A results=([1710]="2" [1709]="9998" ) – BragiPls Jul 20 '18 at 17:02
  • 1
    @BragiPls You have to show *exactly* how you're running the script to reproduce your problem. – Benjamin W. Jul 20 '18 at 17:04
  • @BragiPls, ...so if you run https://gist.github.com/charles-dyfis-net/0f88bdd074c02b29d5eecea12e9c45dd over and over, you eventually get an instance that outputs 1710 on stdout? Could you capture stderr from such an instance? (For example: `while output=$(./runOnce 2>runOnce.trace) && [[ $output = 1709 ]]; do :; done`, then attach `runOnce.trace` to somewhere we can see it?) – Charles Duffy Jul 20 '18 at 17:15
  • You're getting different results randomly even though the input file doesn't change? – Barmar Jul 20 '18 at 17:48
  • Ok prepare to be angry and to laugh all together : if i tell you that in my tests i was not naming my variable SUM but SECONDS.......... I just spent a whole afternoon on that..........this is beautiful – BragiPls Jul 20 '18 at 18:05
  • @CharlesDuffy Quick, the "don't user uppercase variable names" has never been more relevant! ;) – Benjamin W. Jul 20 '18 at 18:07
  • If i had let my variable in place you would have told me right away omg – BragiPls Jul 20 '18 at 18:07
  • So that's why sometimes, for big computations i had +1 – BragiPls Jul 20 '18 at 18:08
  • But i was getting ultra confused because it was hard to reproduce – BragiPls Jul 20 '18 at 18:08

1 Answers1

0

So the explanation was that in my local tests I was using SECONDS instead of SUM. I thought it was a good idea to make it more general for the question. Tip : never do like i just did because more experienced programmers would have spotted the anomaly right away. From bash manual :

SECONDS Each time this parameter is referenced, the number of seconds since shell invocation is returned. If a value is assigned to SECONDS, the value returned upon subsequent references is the number of seconds since the assignment plus the value assigned. If SECONDS is unset, it loses its special properties, even if it is subsequently reset.

Benjamin W. : The "don't user uppercase variable names" has never been more relevant! ;)

BragiPls
  • 17
  • 1
  • 4