0

I have a text file with the structure shown below. I'd like to join them into one column (sum them arithmetically and save as a one column).

file structure:

1   4   1   4
2   5   2   5
3   6   3   6

this what I'd like to get:

10
14
18
0

6 Answers 6

6

For most purposes, I think it's best to use an external program such as AWK or Perl (see cnicutar's answer for an AWK approach); but if you prefer, you can do this in pure Bash, as follows:

while read -a arr ; do
    i=0
    for field in ${arr[*]} ; do
        (( i += field ))
    done
    echo $i
done < input-file.txt > output-file.txt

Or more tersely — but also more hackishly — you could write:

while read ; do
    echo $(( ${REPLY//$'\t'/+} ))
done < input-file.txt > output-file.txt

(the latter is roughly equivalent to the (also hackish) sed-based approaches of various other answers).

Sign up to request clarification or add additional context in comments.

1 Comment

I don't think arr adds anything nonpiratey to the first solution. You could just as well use while read -r; do i=0; for field in $REPLY; do ..., effectively deferring the word splitting from read to for. An alternative for the second solution (for which +1): echo $(($(printf %s+ $REPLY)0)); that works with arbitrary whitespace, including trailing whitespace.
4

How about this:

awk '{ x=0; for(i = 1; i <= NF; i++) x += $i; print x }' file

1 Comment

Thanks. I have a one more question; How to separate this values using commas?
3

@cnicutar gave a standard awk solution, I just add a sed one-liner (with bc) for fun:

kent$  cat f
1 4 1 4
2 5 2 5
3 6 3 6

kent$  sed 's/ \+/+/g' f|bc
10
14
18

the \+ in sed line is just in case your columns are separated by multi-spaces.

as @ruakh suggested, sed 's/[[:space:]]\+/+/g' f|bc is more generic and reliable.

2 Comments

This version of the sed solution is the best so far. It involves only one invocation, doesn't break on consecutive spaces and doesn't use nonstandard syntax. The only improvement I can think of would be to trim leading and trailing space first.
@ruakh you are right, when I posted the answer, the question showed as space... :(, the distance between 'columns' was just one char width. well, [[:space:]] is anyway reliable. I will change the answer
2

Use sed to replace whitespaces with pluses, then bc to get the results:

sed 's/\s\+/+/g' input | bc

1 Comment

Note that \s is non-standard and will not necessarily be available on non-GNU sed. Using [[:space:]] would be equivalent.
1

Alternatively (the awk solution is better, but it's nice too know that there are alternatives :))

sed 's/ /+/g' test.txt | sed -E 's/^(.*)$/echo $((\1))/' | bash

2 Comments

Generating sh code and piping to bash is more dangerous than necessary.
@Sorpigal: that's one of the reasons why I don't recommend using it. It's just here for completeness
1

And here's the same thing in Perl (though I am sure it can be done more tersely):

perl -nle '$s=0; $s+=$_ for split; print $s'

Oh, and to do what your title asks (sum over columns instead of rows):

perl -nle '$i=0; $s[$i++]+=$_ for split; END { print "@s" }'

Because … Perl.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.