Reputation: 347
the text file
student.txt
jane,good,3
bob,bad,2.6
annie,good,2.8
dan,bad,2
first I tried to print all the good student which is successful
#!/bin/bash
while IFS=, read -r -a array; do
[[ "${array[1]}" == "good" ]] || continue
printf "%s \n" "${array[0]}" is a ${array[1]} student"
done < "student.txt"
output
jane is a good student
annie is a good student
next I also want to sum up all the numbers of the third column in the text file after printing the types of student and it was not successful
#!/bin/bash
while IFS=, read -r -a array; do
[[ "${array[1]}" == "good" ]] || continue
printf "%s \n" "${array[0]}" is a ${array[1]} student"
for n in "${array[2]}"; do
total=$( "$total +=$n" | bc )
echo $total
done
done < "student.txt"
output
jane is a good student
+=3: command not found
annie is a good student
+=2.8: command not found
expected output
jane is a good student
annie is a good student
total = 5.8
As I am new to bash scripting , I need to seek help from you guys.
Oh another thing, I can't seem to make good use of awk utility.
even if I tried a simple statement using awk
e.g
awk -F"," "{print $1}" "student.txt"
by right if I am not wrong it should return something like this
output
good
bad
good
bad
but instead it returns me the whole value of the textfile which I have no idea why
my output for awk -F"," "{print $1}" "student.txt"
jane,good,3
bob,bad,2.6
annie,good,2.8
dan,bad,2
so I guess any suggestion use awk method is out.
Upvotes: 1
Views: 760
Reputation: 17188
Pure Bash. The missing floating point arithmetic is emulated.
total=0
while IFS=, read -r -a array
do
[[ "${array[1]}" == "good" ]] || continue
printf "%s \n" "${array[0]} is a ${array[1]} student"
[[ "${array[2]}" =~ ([0-9])(\.([0-9]))? ]]
(( total += 10*${BASH_REMATCH[1]} + ${BASH_REMATCH[3]:-0} ))
done < "student.txt"
printf "total = %d.%d" $((total/10)) $((total%10)
output
jane is a good student
annie is a good student
total = 5.8
Upvotes: 0
Reputation: 46823
This should do (no awk
):
#!/bin/bash
total=0
while IFS=, read -r -a array; do
[[ "${array[1]}" == "good" ]] || continue
printf "%s is a %s student\n" "${array[@]:0:2}"
total=$(bc <<< "$total+${array[2]}")
done < "student.txt"
echo "$total"
Now this forks on bc
for each student. Instead, you could abuse IFS as so:
#!/bin/bash
total=()
while IFS=, read -r -a array; do
[[ "${array[1]}" == "good" ]] || continue
printf "%s is a %s student\n" "${array[@]:0:2}"
total+=( "${array[2]}" )
done < "student.txt"
# Abusing IFS, I know what I'm doing!
IFS="+" bc <<< "${total[*]}"
:)
Or, without IFS abuse and not saving data in memory in an array:
#!/bin/bash
{
while IFS=, read -r -a array; do
[[ "${array[1]}" == "good" ]] || continue
printf >&2 "%s is a %s student\n" "${array[@]:0:2}"
printf "%s+" "${array[2]}"
done < "student.txt"
echo "0"
} | bc
Remark. In the last case, we have to artificially add a 0.
Exercise. Use dc
instead of bc
.
Upvotes: 0
Reputation: 195059
try this one-liner:
awk -F, '$2=="good"{print $1" is good";s+=$3}END{print "total:"s}' file
outputs:
jane is good
annie is good
total:5.8
Upvotes: 4