-4

I have a file containing numbers in many rows and 5 columns like this:

1  2  3  4  5   
6  7  8  9  10   
11 12 13 14 15   
16 17 18 19 20   
21 22 23 24 25   
...

If I want to get sums of the numbers in the 1st row and 3rd row in this way: 1+11, 2+12, 3+13, 4+14, 5+15 which means what I want to see finally is 12 14 16 18 20 What should I do?

12
  • 2
    Please post expected output. Ideally, you should also share what you have tried.
    – Quasímodo
    Mar 20, 2021 at 14:22
  • 1
    It should be trivial to modify one of the answers here for example: How to sum each column and print column name and column sum using awk? Mar 20, 2021 at 14:29
  • 2
    @XYZ, you are expected to research your question a little bit before posting it on Stackexchange, but you just revealed that you have not tried to learn anything about shell programming, or even the shell without programming. Please don't expect this site to be a free consulting service. Mar 20, 2021 at 23:52
  • 2
    @XYZ posting some code showing what you tried and what it did (wrong) would both help us understand how to help you and would also help you explain what you want in a way that would be simpler to understand for everyone
    – Camusensei
    Mar 21, 2021 at 19:39
  • 1
    @XYZ I assumed you hadn't tried anything because you say that you don't understand the term "argument". Any introduction to shell scripting talks about arguments right at the beginning. Mar 21, 2021 at 23:38

3 Answers 3

0

Solution 1

#!/bin/bash
{ read -ra line1; read _; read -ra line3; }
for i in "${!line1[@]}"; do
  result+=("$(( ${line1[i]} + ${line3[i]} ))")
done
printf %s\\n "${result[*]}"

Example:

$ bash script < yourfilename
12 14 16 18 20
$ 

Script explanation

{ read -ra line1; read _; read -ra line3; } This part reads the first three lines of the file, keeping only the first two lines. It also splits them into arrays line1 and line3. It assumes a stream of data from stdin. See the example on how to do that.

for i in "${!line1[@]}"; do result+=("$(( ${line1[i]} + ${line3[i]} ))"); done This part loops over the elements of one of the two arrays, and sums the same elements from line1 and line2. The results are put into a new array called result

printf %s\\n "${result[*]}" Prints the computed array elements space-separated.


Solution 2

Another solution avoiding loops, assuming the input has 5 columns as requested:

#!/bin/bash
{ read a b c d e; read _; read v w x y z; }
echo "$((a+v)) $((b+w)) $((c+x)) $((d+y)) $((e+z))"

Example:

$ cat yourfilename
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
...
$ bash script < yourfilename
12 14 16 18 20
$ 

Script explanation

{ read a b c d e; read _; read v w x y z; } Reads the numbers from line 1 (resp. line 3) into variables a to e (resp. v to z)

echo "$((a+v)) $((b+w)) $((c+x)) $((d+y)) $((e+z))" Prints the sum of the variables space-separated as requested

4
  • I find I'm unable to understand your script. I tried to run it the way you showed. But it told me 'no such file or directory' whilst my file is in the same directory as the bash script. Not sure what's going on there.
    – XYZ
    Mar 20, 2021 at 20:56
  • And also the machine tells me there's a syntax error in the arithmetic operator.
    – XYZ
    Mar 21, 2021 at 14:09
  • Both of those are because you are using < yourfilename instead of using your file name like < example.txt
    – Camusensei
    Mar 21, 2021 at 19:31
  • I have added script explanations as well as a second answer
    – Camusensei
    Mar 22, 2021 at 10:59
-1
$ sed -n '1p;3p' file | datamash -W sum 1-5
12      14      16      18      20

This first uses sed to only output lines 1 and 3. These are then fed into GNU datamash, which is told to sum each individual column from column 1 to 5. The -W instructs datamash to treat any run of whitespaces as field delimiters.

The output is tab-delimited. To get space-delimited output, use the --output-delimiter=' ' option with datamash:

$ sed -n '1p;3p' file | datamash -W --output-delimiter=' ' sum 1-5
12 14 16 18 20
0
-1
awk 'NR==1 || NR==3 { for (i=1; i<=NF; i++) a[i]+=$(i)}END{for (i in a) printf "%s ", a[i]; print ""}'

Example:

$ awk 'NR==1 || NR==3 { for (i=1; i<=NF; i++) a[i]+=$(i)}END{for (i in a) printf "%s ", a[i]; print ""}'' yourfilename
12 14 16 18 20
$ 

EDIT: To stop reading lines from the file after the 3rd, we can exit early. You won't see a sensible difference with files containing less than 10k lines though.

awk 'NR==1 {split($0,a)} NR==3 {for (i in a) printf "%s ", a[i]+$i; print ""; exit}'

Proof that it works with your example:

$ cat yourfilename
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
...
$ awk 'NR==1 {split($0,a)} NR==3 {for (i in a) printf "%s ", a[i]+$i; print ""; exit}' yourfilename
12 14 16 18 20
$ 
3
  • I've tried this one and it doesn't work. I've tried it on a variety of my files, but the results are not the sums of the two numbers of each column in the 1st and 3rd rows
    – XYZ
    Mar 20, 2021 at 18:46
  • @XYZ how about you showed us what was wrong? I clearly followed your example and it works so the data in your files must be different from what you advertise. I also can't update my answers if you don't give me more pieces of information
    – Camusensei
    Mar 21, 2021 at 19:25
  • @XYZ I updated my answer two days after your comment as there was a mistake in the first example, did you try again since then?
    – Camusensei
    Mar 31, 2021 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.