Basically, I need to find average of numbers which are given like:
sh average file1 file (in files can be more than one number)
->10
sh average 5 7
->6
sh average /users/file
->5
echo 5 7 | sh average
6
So basically i wrote my code but it gives me error... I am pretty sure it has to work for first two cases at least.... But I stucked with my error messages ;(
this is my code:
sum=0
n=0
for i in $*
do
if [ -f $i ]
then
while read line
do
n=` expr $n + 1 `
sum=` expr $sum + $line `
done < $i
else
sum=` expr $sum + $i `
n=` expr $n + 1 `
fi
done
average=` expr $sum / $n `
echo $average
Your requirement is not quite clear.
The following reads numbers of files from arguments, or from stdin if no arguments are provided.
The numbers in files or stdin can be placed in columns or rows or both
set -f # no wildcard globbing
sum=0
n=0
from_stdin() {
while read line
do
set -- $line
for i
do
sum=` expr $sum + $i `
n=` expr $n + 1 `
done
done
}
if [ -z "$1" ]
then
from_stdin
else
for i
do
if [ -f "$i" ]
then
from_stdin < "$i"
else
sum=` expr $sum + $i `
n=` expr $n + 1 `
fi
done
fi
if [ $n -gt 0 ]
then
average=` expr $sum / $n `
echo $average
fi
it is strange.....sometimes it gives me an error:
expr: syntax error
expr: syntax error
(standard_in) 1: parse error????
But sometimes it works fine O_o
My code is ok if file contains numbers in columns.... How to fix it in way that code works with files where numbers can be in rows as well, or both?
---------- Post updated at 08:29 PM ---------- Previous update was at 08:26 PM ----------
I tried with your changes but it gives me error like
expr: not a decimal number: 'doc1'
expr: syntax error??
So, did you invoke your script with doc1 as an operand (when there is no file named doc1), or did you specify a file as an operand where the file exists and contains the word doc1 instead of just numbers?
Thanks I found out what is wrong. But can you recommend smth with previous comment about how to modify code with file containing numbers in row also.....
Of course I could. Depending on what shell you're using and what operating system you're using, the script you have is probably not only not working in some cases, but also very inefficient in the cases that are working. So, to provide you with a reasonable, working solution, how about answering some questions first:
What shell are you using?
If you aren't using the Korn shell, is it OK to use the Korn shell instead of the shell you're using?
Do you have access to a 1993 or later version of ksh?
What operating system are you using?
What is the name of your file that contains one or more rows with more than one number in a row?
What is the actual contents of the file that contains more than one number in one or more rows?
What happens when you use set -xvf instead of set -f to trace the commands your script is running (so you can actually see the expr command that is failing)?
Show us some sample invocations of your script, the contents of any files named in those sample invocations, and the output that you expect from each of those sample invocations!
I m using Mac Pro..... So it gives you information what I am using i guess....
But as long as you recommend the strategy or what i have to add then you do not need to rewrite my code.
Basically, This is my piece of code..I just think that we can add smth for case with rows of numbers in file.
One more thing:
for example we have file1 and file2:
cat file1
-> 13 4 6 7 3
cat file2
-> 3
5
6
so when i run my code:
sh average file1 file2
->10 (WHICH is average of all numbers)
i can have many files with numbers in rows or columns or both. Space between numbers also can be double or triple etc. Hope u help me.
I thought also to add to while loop tr ' \n ' ' , ' and tr ' ' ' , '
#/bin/sh
check(){
if [ -z "$1" ];
then echo "No user input";
exit;fi
}
check $1
sum=0
n=0
for i in $*
do
echo $i
if [ -f $i ]
then
while read line
do
n=` expr $n + 1 `
sum=` expr $sum + $line `
done < $i
else
sum=` expr $sum + $i `
n=` expr $n + 1 `
fi
done
average=$(echo "scale=3; $sum/$n" | bc -l )
# average=` expr $sum / $n `
echo $average
Thank u:) One more thing it is more relating to the input from pipes...for example
echo 5 3 | sh my_code. What I need to add to my code for accepting input from pipes? Would appreciate if you tell what I need to add in my piece of code...thanks
check(){
if [ -z "$1" ];
then echo "No user input";
exit;fi
}
check $1
sum=0
n=0
t=0
for i in $*
do
if [ -f $i ]
then
while read line
do
for j in $line
do
n=` expr $n + 1 `
sum=` expr $sum + $j `
done
done< $i
else
sum=` expr $sum + $i `
n=` expr $n + 1 `
fi
done
average=$(echo "scale=2; $sum/$n" | bc -l )
# average=` expr $sum / $n `
echo $average
You never did answer my question about what shell you're using and whether or not you had access to a 1993 or later version of the Korn shell. You've said you're using a Mac, so if you're using a recent version of OS X you do have a recent Korn shell. Translating your script to just use ksh built-ins (and adding a little structure to your indentation), the following Korn shell script seems to do what you want without all of the invocations of expr and bc:
#!/bin/ksh
n=0 # initialize number of numbers
sum=0 # initialize sum of numbers
if [ $# -gt 0 ]
then for i in $* # Process command line args
do if [ -f $i ]
then while read line # read from file named by arg
do for j in $line # for each number on the line
do ((n++)) # increment count and update sum
((sum += j))
done
done < $i
else ((sum += i)) # process command line number
((n++))
fi
done
else while read line # Process numbers from stdin
do for j in $line
do ((n++))
((sum += j))
done
done
fi
average=$(( (sum + 0.0) / n)) # calculate average
printf "%.2f\n" $average # round to 2 decimal places
Obviously, there should be some verification that arguments that are not filenames on the command line and that data read from files (including standard input) is numeric data, but I'll leave that as an excercise for the reader. If there are no command line operands, this script will read data from standard intput. In this case, it does not care if the standard input is from the user typing at a terminal, redirected from a file, or a pipe.
The logic in this script follows the same logic used in your last script except that it reads from standard input instead of printing a diagnostic message if there are no operands given to your script.