Shell scripting, finding average of loop results - linux

I made a loop to find the results of calculating each number from (1 to 10 mod 5) + 2
for (( i = 0; i <= 10; i++))
do
calculate=$(( i % 5 + 2 ))
echo "($i % 5) + 2 = " $calculate
done
average=$(($calculate/10))
echo $average`
My problem is fixing my code so that I can take all the results of the loop and find the average of them
Its returning back 0 for the average

You have to keep a full total - ($calculate/10) is just the last iteration. Keep a running total initialized to zero before the loop total = 0 ... then add the calculated value to the total in each iteration of the loop total = $( $total + $calculate ) Then the average is total/10 (not calculate/10).
#!/bin/bash
total=0
for (( i = 0; i <= 10; i++))
do
calculate=$(( i % 5 + 2 ))
total=$(( $total + $calculate ))
echo "($i % 5) + 2 = " $calculate
done
#average=$(($calculate/10))
average=$(($total/10))
echo $average

Related

How to code the program in the Shell Script [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
How to code the program in the Shell Script to calculate the sum of the Fibonacci series with the upper limit input from the keyboard? Input for example: "Enter the limit of the Fibonacci series? 10". and the result: 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13 + 21 + 34 = 88
#!/bin/bash
if [ $# -eq 1 ]
then
Num=$1
else
echo -n "Enter the limits of the Fibonacci sequence : "
read Num
fi
a=0
b=1
echo "Result : "
for (( i=0;i<=Num;i++ ))
do
echo -n “$a + “
n=$((a+b))
a=$b
b=$n
done
echo
Anyone know how to get the results?
my expected output is:
Enter the limits of the Fibonacci sequence : 10
Result : 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13 + 21 + 34 = 88
I'm stuck trying
$ cat fib
#!/bin/bash
Num=${1-5}
a=0
b=1
unset s
printf "Result: "
for (( i=0; i<Num; i++ )); do
printf "${s:+ + }$a"
s=$(($s + $a))
n=$((a+$b))
a=$b
b=$n
done
echo " = $s"
$ ./fib 5
Result: 0 + 1 + 1 + 2 + 3 = 7
$ ./fib 10
Result: 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13 + 21 + 34 = 88
This works:
a=1;
b=0;
sum=$a;
for ((i=1;i<10-1;++i)); do
((tmp=b));
((b=a));
((a+=tmp));
((sum+=a));
done;
echo $sum;
Output from my terminal:
[ichramm#hypernova][Wed, 28 Oct 16:19:24][~]
$ a=1; b=0; sum=$a; for ((i=1;i<10-1;++i)); do ((tmp=b)); ((b=a)); ((a+=tmp)); ((sum+=a)); done; echo $sum;
88

"Attempted assignment to a non-variable" in bash

I'm new to Bash and I've been having issues with creating a script. What this script does is take numbers and add them to a total. However, I can't get total to work.It constantly claims that total is a non-variable despite it being assigned earlier in the program.
error message (8 is an example number being entered)
./adder: line 16: 0 = 0 + 8: attempted assignment to non-variable (error token is "= 0 + 8")
#!/bin/bash
clear
total=0
count=0
while [[ $choice != 0 ]]; do
echo Please enter a number or 0 to quit
read choice
if [[ $choice != 0 ]];
then
$(($total = $total + $choice))
$(($count = $count + 1))
echo Total is $total
echo
echo Total is derived from $count numbers
fi
done
exit 0
Get rid of some of the dollar signs in front of the variable names. They're optional inside of an arithmetic context, which is what ((...)) is. On the left-hand side of an assignment they're not just optional, they're forbidden, because = needs the variable name on the left rather than its value.
Also $((...)) should be plain ((...)) without the leading dollar sign. The dollar sign will capture the result of the expression and try to run it as a command. It'll try to run a command named 0 or 5 or whatever the computed value is.
You can write:
((total = $total + $choice))
((count = $count + 1))
or:
((total = total + choice))
((count = count + 1))
or even:
((total += choice))
((count += 1))

Shell for loop, stopping at declaration

I'm trying to write a for loop that goes from 1 to 10, then calculates ( 1 through 10 mod 5) + 2. After that I want to display it like this (1 to 10 mod 5) + 2 = answer. However i'm getting an error at the beginning of the loop which is a syntax error.
for (( i = 0; i <= 10; i++)); do
calculate=(i % 5) + 2
echo ("("i "% 5) + 2" calculate)
done
Try these changes:
calculate=$(( i % 5 + 2 ))
# $(( ... )) is the shell's way to do arithmetic
echo "($i % 5) + 2 = " $calculate
# $x is a way to refer to the value of variable x
# (also inside a double-quoted string)
The for loop header is actually OK.

Average of multiple files without considering missing values

I want to calculate the average of 15 files:- ifile1.txt, ifile2.txt, ....., ifile15.txt. Number of columns and rows of each file are same. But some of them are missing values. Part of the data looks as
ifile1.txt ifile2.txt ifile3.txt
3 ? ? ? . 1 2 1 3 . 4 ? ? ? .
1 ? ? ? . 1 ? ? ? . 5 ? ? ? .
4 6 5 2 . 2 5 5 1 . 3 4 3 1 .
5 5 7 1 . 0 0 1 1 . 4 3 4 0 .
. . . . . . . . . . . . . . .
I would like to find a new file which will show the average of these 15 fils without considering the missing values.
ofile.txt
2.66 2 1 3 . (i.e. average of 3 1 4, average of ? 2 ? and so on)
2.33 ? ? ? .
3 5 4.33 1.33 .
3 2.67 4 0.66 .
. . . . .
This question is similar to my earlier question Average of multiple files in shell where the script was
awk 'FNR == 1 { nfiles++; ncols = NF }
{ for (i = 1; i < NF; i++) sum[FNR,i] += $i
if (FNR > maxnr) maxnr = FNR
}
END {
for (line = 1; line <= maxnr; line++)
{
for (col = 1; col < ncols; col++)
printf " %f", sum[line,col]/nfiles;
printf "\n"
}
}' ifile*.txt
But I can't able to modify it.
Use this:
paste ifile*.txt | awk '{n=f=0; for(i=1;i<=NF;i++){if($i*1){f++;n+=$i}}; print n/f}'
paste will show all files side by side
awk calculates the averages per line:
n=f=0; set the variables to 0.
for(i=1;i<=NF;i++) loop trough all the fields.
if($i*1) if the field contains a digit (multiplication by 1 will succeed).
f++;n+=$i increment f (number of fields with digits) and sum up n.
print n/f calculate n/f.
awk '
{
for (i = 1;i <= NF;i++) {
Sum[FNR,i]+=$i
Count[FNR,i]+=$i!="?"
}
}
END {
for( i = 1; i <= FNR; i++){
for( j = 1; j <= NF; j++) printf "%s ", Count[i,j] != 0 ? Sum[i,j]/Count[i,j] : "?"
print ""
}
}
' ifile*
assuming file are correctly feeded (no trailing empty space line, ...)
awk 'FNR == 1 { nfiles++; ncols = NF }
{ for (i = 1; i < NF; i++)
if ( $i != "?" ) { sum[FNR,i] += $i ; count[FNR,i]++ ;}
if (FNR > maxnr) maxnr = FNR
}
END {
for (line = 1; line <= maxnr; line++)
{
for (col = 1; col < ncols; col++)
if ( count[line,col] > 0 ) printf " %f", sum[line,col]/count[line,col];
else printf " ? " ;
printf "\n" ;
}
}' ifile*.txt
I just check the '?' ...

Read all the entries of a matrix using shell script

I have a matrix,
A(i,j), i=1,m and j=1,n
I can read it in C and FORTRAN, but I can't read it in shell script. I know this is a very simple question, but I am very new to shell script. I want to read all entries and do some calculation e.g. I have a matrix:
A= 1 0 1 1
2 1 0 2
1 0 0 3
1 2 3 0
Now I want to compare each 0 with its above, below, left and right values. Finally I want to do some computation (lets say sum) with these four values around each zero. In the above example the result will be- for five zeros
1st zero: 3
2nd zero: 4
3rd zero: 4
4th zero: 6
5th zero: 6
So in FORTRAN, I can do it by reading all the values as
do j=1,n
do i=1,m
if (A(i,j) .eq. 0) then
B(i,j)=A(i-1,j)+A(i+1,j)+A(i,j+1)+A(i,j-1)
enddo
enddo
But I want to do it in shell script. How to do?
Assuming that data are given in "test.dat" (with no "A = "), I tried it anyway...
#!/bin/bash
inpfile="test.dat"
L=100 # some large value
for (( i = 0; i < L; i++ )) {
for (( j = 0; j < L; j++ )) {
A[ L * i + j ]=0
}
}
i=1
while read buf; do
inp=( $buf ); n=${#inp[#]}
if (( L <= n+1 )); then echo "L is too small"; exit -1; fi
for (( j = 1; j <= n; j++ )) {
A[ L * i + j ]=${inp[j-1]}
}
(( i++ ))
done < $inpfile
nzeros=0
for (( i = 1; i <= n; i++ )) {
for (( j = 1; j <= n; j++ )) {
if (( ${A[ L * i + j ]} == 0 )); then
(( nzeros++ ))
B[ nzeros ]=$(( \
${A[ L * (i-1) + j ]} + \
${A[ L * (i+1) + j ]} + \
${A[ L * i + j+1 ]} + \
${A[ L * i + j-1 ]} ))
fi
}
}
for (( k = 1; k <= nzeros; k++ )) {
printf "%dst zero: %d\n" $k ${B[k]}
}
Conclusion: Very painful. Fortran is recommended...(as expected)

Resources