LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   arithmetic operation in bash (https://www.linuxquestions.org/questions/linux-newbie-8/arithmetic-operation-in-bash-867748/)

xeon123 03-10-2011 11:55 AM

arithmetic operation in bash
 
Hi,
I've the following input file (sorted.txt)

Code:

A 1
A 1
A 1
B 3
B 2

and I want to sum all the numbers by letter and put it in an array. I want the following result:
Code:

A 3
B 5

I've created this script:

Code:

cat sorted.txt | while read line
do
    KEY=$(echo "$line" | awk '{ print $1 }');
    VALUE=$(echo "$line" | awk '{ print $2 }');

    if [[ -n map[$KEY] ]]
    then
        old=map[$KEY];
        map[$KEY]=$old+$VALUE;
    else
        map[$KEY]=$VALUE;
    fi
done

But the problem is that it doesn't work. What's wrong?

tsg 03-10-2011 02:46 PM

Code:

map[$KEY]=$old+$VALUE;
should read

Code:

map[$KEY]=$(( $old+$VALUE ));

colucix 03-10-2011 02:55 PM

As tsg said. The $ sign is not necessary inside the arithmetic operator:
Code:

map[$KEY]=$(( old+VALUE ));
An alternative using only awk:
Code:

awk '{map[$1]+=$2}END{for (i in map)print i, map[i]}' sorted.txt

tsg 03-10-2011 02:58 PM

Quote:

Originally Posted by colucix (Post 4285973)
As tsg said. The $ sign is not necessary inside the arithmetic operator:

This is true. I generally add it out of habit for clarity, though.

xeon123 03-10-2011 03:30 PM

Ok, thanks for the help.
I'm going to give another hint:

Bash spawns a new sub-shell when piping commands together. Since Bash is picky about scoping variables to sub-shells, my script doesn't work like I expected it to.

Using this "while" will help a lot with the rest of the script.

Code:

while read line
do
let COUNT=$COUNT+1
done < filename.txt
echo $COUNT


xeon123 03-10-2011 03:33 PM

This will work.

Code:

while read line
do
    KEY=$(echo "$line" | awk '{ print $1 }');
    VALUE=$(echo "$line" | awk '{ print $2 }');

    old=${map[$KEY]};
    map[$KEY]=$(( old+VALUE ))
done < A.txt


grail 03-10-2011 07:12 PM

Quote:

This will work.
True, but unless the data is more complicated I would suggest either using bash or awk, it would seem pointless to use both.
colucix has already provided an appropriate awk script.
As for all bash:
Code:

#!/bin/bash

declare -A map

while read -r KEY VALUE
do
    (( map[$KEY] += VALUE ))
done<A.txt



All times are GMT -5. The time now is 04:32 PM.