1

Write a script that expects a file as its first argument. Some lines of the file will consist of integers 0 - 1000. The script should select the lines matching the previous criteria and print out their average to stdout (average of n integers is their sum divided by n).

And the file given looks like this:

22
78907
77 88 99 0000
need 11 gallons of water
0
roses are red
11

Example output:

11

Explanation: (22 + 11 + 0) / 3 = 11

I have tried already with this code:

#!/bin/bash

sum=0
ind=0

while IFS='' read -r line || [[ -n "$line" ]]; do
   if [[ $line =~ ^[a-zA-Z\ ]+$ ]]
   then
        ${sum}=${sum}+${#line} 
        ${ind}=${ind}+1 
        echo ${sum}
   fi        
done < "$1"

value=${sum}/${ind}
echo ${value}

the print of this code is always 0/0 and some errors like:

./test1: line 9: 0=0+13: command not found
./test1: line 10: 0=0+1: command not found

Any ideas?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Danut Chirila
  • 45
  • 1
  • 1
  • 6

1 Answers1

2

Part of the issue with your script is answered here.. Your variable assignments are incorrect. You only use the $ to refer to a variable that has already been assigned. The assignment process drops the dollar sign.

The other issue you're having is that your arithmetic is not being expressed within an arithmetic expression.

Note that you can use use arithmetic expansion to handle your variables:

  if [[ $line =~ ^[a-zA-Z\ ]+$ ]]; then
      (( sum += ${#line} ))
      (( ind++ ))
      printf '%s\n' "$sum"
  fi

and later ...

value="$(( sum / ind ))"
printf '%s\n' "$value"

Beware that bash can only deal with integer math, floats are truncated. For more advanced math, consider using bc or dc (which are not built in to bash, they are separate tools that may need to be installed on your system) or another language like awk or perl which can do the same thing with better performance and more precise math.

That said, you can "fake" a couple of decimal places with a few extra lines of code and string manipulation, if you really need to:

$ sum=100; ind=7
$ printf -v x '%d' "$((${sum}00/${ind}))"
$ printf '%d.%d\n' "${x%??}" "${x:$((${#x}-2))}"
14.28

The first printf has division which multiplies the dividend by 100 (by adding two zeroes after it). The resultant quotient is then split with the second printf to insert the decimal point. This is a hack. Use tools that support real math.

ghoti
  • 45,319
  • 8
  • 65
  • 104
  • hei, i did what you said, but actually I modified the regex in that if statement, so now it looks like this `^([1000|[0-9]'\n'*[0-9]{0,2}'\n')` after that i put _+$_ but i'm not sure what this one does i'm newbie in bash :D oh i forgot, now i get this error: `./test1: line 23: sum / ind : division by 0 (error token is "ind ")` – Danut Chirila Jan 26 '18 at 21:29
  • @DanutChirila, if you want to write and test regular expressions, https://regex101.com/ is an excellent resource. What are you trying to match with your regex? This one seems to imply "either a single digit or 1000, followed by zero or more newlines, followed by up to two digits and another newline" .. but note that as you've written your example above, the `\n` would not be expanded as a newline. Besides, `$line` would never contain a newline because it reads input *line by line*. – ghoti Jan 26 '18 at 22:00
  • as i mentioned above, i try to get only the rows with numbers between 0-1000 and make their average... – Danut Chirila Jan 26 '18 at 22:07
  • Okay, but that's not what the regex recognizes. Test it out at the link I provided, and consider using arithmetic evaluation to check for numeric values rather than regex. There are places for regex, but [verifying numeric values probably can be done better in other ways](https://stackoverflow.com/a/9038554/1072112). – ghoti Jan 26 '18 at 22:24
  • so you say that i have to find another way to get only the numbers from the file... – Danut Chirila Jan 26 '18 at 22:40
  • I'm not in a position to tell you what you *have* to do. There are many ways to achieve any goal, and usually you only have to reach the goal. This answer, and the links in my comments, may recommend *better* ways to do that, but in the end, the most important factor in how you write software is that you understand what you've written, so that you can maintain it and make changes in 6 months or 3 years when you're called on to change it. – ghoti Jan 26 '18 at 23:37