Подсчитать сумму каждого столбца в файле

9

В файле с различным количеством столбцов, разделенных пробелом '', Как посчитать сумму столбцов. Пример показал бы необходимость:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

Тогда результат будет:

  • для столбца 1 (1 + 2 + 4 + 1) = 8
  • для столбца 2 - 11
  • для колонки 3 - 7
  • для колонки 4 - 5
Maythux
источник

Ответы:

12

С помощью awk

awk '{for (i=1;i<=NF;i++) sum[i]+=$i;}; END{for (i in sum) print "for column "i" is " sum[i];}' FileA
for column 1 is 8
for column 2 is 11
for column 3 is 7
for column 4 is 5
steeldriver
источник
Хорошее использование массивов, хотя я думаю, что это можно упростить, просто посчитав сумму и распечатав ее сразу
Сергей Колодяжный
Действительно, это лучший ответ здесь.
Кос
5

Используйте numsumдля этой задачи и отделите между обработкой данных и выводом результатов.

Установить num-utils, нам нужноnumsum

sudo apt-get install num-utils

И начать с

numsum -c <your_file_name>

пример

$ cat "File A"
1 2 
2 3
4 5 6 
1 1 1 5

$ numsum -c "File A"
8 11 7 5

или с вашим желаемым форматом:

$ numsum -c "File A" | awk '{for(i=1;i<=NF;i++) {print "for column "i" is "$i}}'
for column 1 is 8
for column 2 is 11
for column 3 is 7
for column 4 is 5

от man numsum

-c      Print out the sum of each column.

примеры из man numsum

EXAMPLES

   Add up the 1st, 2nd and 5th columns only.

       $ numsum -c -x 1,2,5 columns
       15 40 115

   Add up the rows of numbers of a file.

        $ numsum -r columns
        55
        60
        65
        70
        75
AB
источник
3
#!/bin/sh

while read a b c d; do
    col1=$((col1 + a))
    col2=$((col2 + b))
    col3=$((col3 + c))
    col4=$((col4 + d))
done < File_A

echo $col1 $col2 $col3 $col4
Флориан Диш
источник
Можно, наверное, сказать (( col1 += a ))и т. Д. Также echo "..."безопаснее, как иwhile IFS= read -r ...
fedorqui
@fedorqui echoбезопасно использовать таким образом, чтобы отображать числа, $IFSзначения по умолчанию в пробелах, и ожидается, что они будут числами, поэтому нет необходимости иметь обратную косую черту. Единственным недостатком этого ответа является необходимость знать количество столбцов до выполнения.
Кос
@kos никогда не знаешь, каким может быть входной файл. И несмотря на то, что в ОП упоминаются только цифры, всегда полезно готовиться к худшему. См. Как я могу прочитать файл (поток данных, переменную) построчно (и / или поле за полем)? для великолепного объяснения.
Федорки
@fedorqui По твоему собственному утверждению, я думал, что это было вне обсуждения; Если вы хотите сделать точки, предполагая, что входной файл может содержать что-то отличное от цифр, вам не хватает явной части: проверки, является ли прочитанное числом. Добавление строк и использование echo "[...]"для правильной печати того, что вы не хотите выводить, не имеет смысла.
Кос
@kos Конечно, можно сказать, echo $varи while read a b cэто работает здесь. Тем не менее, вы привыкнете писать его слабо, и однажды вы получите странные ошибки при обработке более сложного файла. Тогда вы заметите, что цитируете переменные, и использование while IFS= read -r ...было безопаснее и скажет: «О да, Федорки был прав, я надеюсь, что он мог бы обнять его, чтобы выразить благодарность!».
Федорки
3

Судя по комментариям к вашему собственному ответу, вам нужна только сумма по одному столбцу за раз. Если это так, вот не-awk способ сделать это:

cut -d' ' -f3 FileA | grep . | paste -s -d+ | bc

где вы могли бы заменить 3интересующий вас номер столбца.

Цифровая травма
источник
0

Вот однострочный подход к Perl-скрипту. Это основано на использовании -aфлага, который позволяет автоматически разбивать текущую строку с -nфлагом в массив @F. Все, что нам нужно сделать, это перебрать эти элементы и добавить их к соответствующему индексу в $sumмассиве, таким образом, фактически каждый элемент массива является суммой для каждого соответствующего столбца. Наконец, мы печатаем результат в ENDблоке кода.

$ perl -lane '$j=0;foreach $i (@F){$sum[$j]+=$i; $j+=1;}; END{print join("\n",@sum)} ' input.txt                                                     
8
11
7
5

В качестве альтернативы приведем полный подход к сценарию Perl. Он основывается на разбиении каждой строки на массив и итерации по каждому элементу в этом массиве, добавляя каждое число к их соответствующей возможности в @sumsмассиве. Сценарий распечатывает каждую строку, а затем создает отчет для каждого столбца. Печать каждой строки можно удалить, добавив #передprintf("%s",$line);

#!/usr/bin/env perl
use strict;
use warnings;

open(my $fh,"<",$ARGV[0]); 
my $i = 0;
my @sums;

while(my $line = <$fh>) { 
    printf("%s",$line);
    my @nums = split(" ",$line);
    my $j = 0;
    foreach my $num (@nums){
        $sums[$j] += $num;
        $j += 1;
    }

}

my $k = 0;
foreach my $sum (@sums){
    printf("- column %d sum: %d\n",$k,$sum);
    $k+=1;
}

close($fh);

Использование простое chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Например:

$ ./sum_columns_2.pl input.txt                                                                                                                       
1 2 
2 3
4 5 6 
1 1 1 5
- column 0 sum: 8
- column 1 sum: 11
- column 2 sum: 7
- column 3 sum: 5
Сергей Колодяжный
источник
-2

Простое решение:

awk '{sum += $i} END {print sum}' file

Замените i номером столбца, например column1:

awk '{sum += $1} END {print sum}' file

вывод:

8
Maythux
источник
3
Это только один столбец. Вы не соответствуете вашим собственным спецификациям.
Оли
Я не утверждал, что хочу получить все результаты в одной команде. плюс этот ответ просто нужен цикл, и он будет идеальным
Maythux
Так зачем понижать голос?
Maythux