LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   little calculation in script. (https://www.linuxquestions.org/questions/linux-newbie-8/little-calculation-in-script-820651/)

pinga123 07-19-2010 04:28 AM

little calculation in script.
 
How would i calculate following values.

Initial file

10 3
20 4
How would i calculate 3rd column which should be addition of value in 1 and 2nd column.
File after calculation
10 3 13
20 4 24

zirias 07-19-2010 04:44 AM

although this is probably possible with shell scripting, it sounds like a typical application for perl:
Code:

#!/usr/bin/perl
use strict;

while (<STDIN>)
{
  if (/^(\d+)\s+(\d+)/)
  {
    print "$1 $2 " . ($1 + $2);
  }
}


David the H. 07-19-2010 04:47 AM

Could you give more details please? Are the numbers only whole integers or do they involve decimals, negative numbers, or such? Is there anything in the file except the numbers? What is the exact situation?

Assuming a simple file though, awk should be enough.
Code:

awk '{print $1,$2,$1+$2}' file.txt >newfile.txt
Note that you'll have to output to a temporary file, and replace the original afterwards.

pinga123 07-19-2010 05:57 AM

Thanks for your quick replies.

10 3
20 4
How would i calculate the total in each row for example
row1total=30
row2total=7
10 3
20 4

also wanted to know how to save the output of above calculation in variable?

zirias 07-19-2010 06:07 AM

You mean .. the sum of each column?

Ok, now I'd really suggest to learn perl, it was initially done for things like that :)

basic idea: declare an array for the columns (containing one array reference per column). loop over the lines like shown in the little perl snippet above, but storing each time the values found in the correct column-array. use these later to calculate your sums.

It will take you a while :)

pinga123 07-19-2010 07:03 AM

Quote:

Originally Posted by zirias (Post 4037929)
You mean .. the sum of each column?

Ok, now I'd really suggest to learn perl, it was initially done for things like that :)

basic idea: declare an array for the columns (containing one array reference per column). loop over the lines like shown in the little perl snippet above, but storing each time the values found in the correct column-array. use these later to calculate your sums.

It will take you a while :)

This is helpful but do i really need to learn perl or it can be done using shell script also .

I know perl has lot of such functionality but i wonder how shell script lacks in this feature?

Dinithion 07-19-2010 07:09 AM

This is possible, but awk and perl is more slick then bash scripts.

to summarize a column, you can do this f.eks. like this:

Code:

for i in $(cat inputfile); do
let TMP=$TMP+$i
done
echo $TMP

Now you have to do this for each column, you can use cut to only read a single column

Code:

cut -f 1 -d ' '
will output the first column of a line. Combine this with the first code-block I wrote, and you are near a solution :)

Edit:

Ops, seems like I was a little trigger happy there. It looks like for read a file word by word, and not line by line. Then another solution is needed.

GrapefruiTgirl 07-19-2010 07:16 AM

Bash/shell is not 'lacking' this feature; you can do basic arithmetic using shell scripting (i.e. Bash shell, or your choice of shell I suppose) but Bash does not do floating-point, only whole-integer operations. For example:

Code:

sasha@reactor: a=3
sasha@reactor: b=4
sasha@reactor: echo $((a+b))
7
sasha@reactor:

So, not difficult. But you'd need to do some sort of loop to read the file and process it, and dump the results to the new file. If you wanted to process floating-point (decimals/fractions) you would have to incorporate something in addition to bash, such as `bc`, which is the "Basic Calculator", and is quite capable of doing most math you can throw at it.

I believe the AWK solution offered by David in post #3 is going to be the most practical, simple, easy-to-understand way to do what you want. You could eventually come up with a dozen+ variations on how to do what you ask, but post #3 is the neatest.

If you absolutely MUST use 100% Bash, do a little reading/research about the bash functions you think you will need (read function, for/while loops, echo command, shell redirection, etc..), begin to construct a script and show us what you've got, and we will help you with your script.

Sasha

zirias 07-19-2010 07:19 AM

Although I like post #3 for its simplicity, it only solves the problem from #1 (calculate the sums of the rows), not that from #4 (columns) ;)

Dinithion 07-19-2010 07:27 AM

Code:

#!/bin/bash

FILE=<input file>
COL=<column>
SUM=0
for i in $(cut -d ' ' -f $COL $FILE); do
        let SUM=$SUM+$i
done
echo $SUM
unset SUM COL FILE

This works for me :)
This is just problem #4 tough.

GrapefruiTgirl 07-19-2010 07:30 AM

The output is columnized, as far as I can see. To demonstrate:

Code:

sasha@reactor: awk '{print "Row "NR": "$1" "$2" Sum="$1+$2}' mathsed
Row 1: 1 4 Sum=5
Row 2: 2 5 Sum=7
Row 3: 3 6 Sum=9
sasha@reactor:

Those are columns, no? :)

MTK358 07-19-2010 07:58 AM

I also think this is a perfect Perl application.

Code:

my @rows;

while (<STDIN>) {
    if (/([0-9]+)[ \t]+([0-9]+)/) {
        my $sum = $1 + $2;
        push @rows, $sum;
        print "$1 $2 $sum\n";
    }
}

I don't know what you meant by "saving the result to a variable", here I just put all the sums into an array called @rows that you can access later.

zirias 07-19-2010 01:44 PM

Quote:

Originally Posted by GrapefruiTgirl (Post 4037997)
Those are columns, no? :)

Take a close look at posting #4. Although the OP writes "row1" and "row2", he actually gives the columns sums as examples. Your code prints columns, but not their sums (only those of the rows).

If the intention of the OP really is to sum up rows as well as columns, he's probably even going further -- this is perfectly suited for perl :)

GrapefruiTgirl 07-19-2010 01:49 PM

Thanks for pointing that out zirias - now I see ;)

Tinkster 07-19-2010 01:56 PM

Code:

$ cat pinga.txt
10 3
20 4
$ awk '{col1+=$1; col2+=$2; print $1" "$2" "$1+$2}END{print col1 " "col2}' pinga.txt
10 3 13
20 4 24
30 7
$


zirias 07-19-2010 02:12 PM

Ok, i admit, i never learned awk ... seems quite powerful, too

Tinkster 07-19-2010 03:59 PM

Quote:

Originally Posted by zirias (Post 4038469)
Ok, i admit, i never learned awk ... seems quite powerful, too

perls little brother, if you wish ... ;}

pinga123 07-20-2010 02:06 AM

I have started developing the script as said.

This is how my script looks.
it takes the output of free -m and insert into a file for given amount of time.

Code:

#!/bin/bash

echo "Enter Time Interval"
read inputtime

rm -rf /tmp/raminfo
i=0
echo "RAM Information for last $inputtime Seconds" > /tmp/raminfo
while [ $i -le $inputtime ]
do
free -m | grep Mem >> /tmp/raminfo
sleep 1
i=$( expr $i + 1 )
done

Output.
Code:

# ./test
Enter Time Interval
10
# cat /tmp/raminfo
RAM Information for last 10 Seconds
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260
Mem:          503        468        34          0        58        260

How would i create and attach new column indicating RAM utilization.
This can be done by taking col3/col2 but i m getting following error.

Code:

# cat /tmp/raminfo | awk '{print $3/$2}'
awk: (FILENAME=- FNR=1) fatal: division by zero attempted


GrapefruiTgirl 07-20-2010 05:04 AM

1) The error is probably coming from this line:

Code:

RAM Information for last 10 Seconds
Which is the first line of the file, and which AWK is interpreting (or trying to) as numbers, which it is not, hence division by zero. You need a method of skipping over that first line of the file, or selecting only the lines which actually have the numerical data that you want. Also, AWK can read files all by itself, so you don't really need that `cat` there. I would try something like below, which places a simple regexp (regular expression) into the awk, which will match only the lines beginning with "Mem:" and ignore the rest:

Code:

awk '/^Mem:/ { print $3 / $2}' /tmp/raminfo
2) I'm not sure if the desired output you want from this is a XX/YY format, or if you actually planned to do that division operation $3/$2, but if you want the division thing, you may wish to multiply the result by 100 to get a percent, which would be maybe more pleasing to the eye. OR, if you just want a display of XX/YY then you'll need to put the / into "double quotes".

3) Finally a suggestion/idea which is maybe just a matter of preference for me: when doing simple shell math, you could use i=$((i+1)) instead of i=$( expr $i + 1 ) if for no other reason than that there are three less characters to type :D but it's up to you.

Cheers!

pinga123 07-20-2010 06:17 AM

Quote:

Originally Posted by GrapefruiTgirl (Post 4039270)
1) The error is probably coming from this line:

Code:

RAM Information for last 10 Seconds
Which is the first line of the file, and which AWK is interpreting (or trying to) as numbers, which it is not, hence division by zero. You need a method of skipping over that first line of the file, or selecting only the lines which actually have the numerical data that you want. Also, AWK can read files all by itself, so you don't really need that `cat` there. I would try something like below, which places a simple regexp (regular expression) into the awk, which will match only the lines beginning with "Mem:" and ignore the rest:

Code:

awk '/^Mem:/ { print $3 / $2}' /tmp/raminfo
2) I'm not sure if the desired output you want from this is a XX/YY format, or if you actually planned to do that division operation $3/$2, but if you want the division thing, you may wish to multiply the result by 100 to get a percent, which would be maybe more pleasing to the eye. OR, if you just want a display of XX/YY then you'll need to put the / into "double quotes".

3) Finally a suggestion/idea which is maybe just a matter of preference for me: when doing simple shell math, you could use i=$((i+1)) instead of i=$( expr $i + 1 ) if for no other reason than that there are three less characters to type :D but it's up to you.

Cheers!

Thanks for your help.


All times are GMT -5. The time now is 01:36 AM.