Hitung jumlah setiap kolom dalam file

9

Dalam file dengan jumlah kolom yang berbeda dibatasi oleh spasi '', Cara menghitung jumlah kolom. Contoh akan menunjukkan kebutuhan:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

Maka hasilnya adalah:

  • untuk kolom 1 (1 + 2 + 4 + 1) = 8
  • untuk kolom 2 adalah 11
  • untuk kolom 3 adalah 7
  • untuk kolom 4 adalah 5
Maythux
sumber

Jawaban:

12

Menggunakan 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
sumber
Baik penggunaan array meskipun saya pikir itu bisa disederhanakan dengan hanya menghitung jumlah dan mencetaknya segera
Sergiy Kolodyazhnyy
Memang ini jawaban terbaik di sini.
kos
5

Gunakan numsumuntuk tugas itu dan pisahkan antara pemrosesan data dan hasilkan hasilnya.

Instal num-utils, kita perlunumsum

sudo apt-get install num-utils

Dan mulailah dengan

numsum -c <your_file_name>

Contoh

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

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

atau dengan format yang Anda inginkan:

$ 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

dari man numsum

-c      Print out the sum of each column.

contoh dari 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
sumber
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
Florian Diesch
sumber
Anda mungkin bisa mengatakan (( col1 += a )), dll. Juga, echo "..."lebih aman, dan jugawhile IFS= read -r ...
fedorqui
@ fedorqui echoaman digunakan seperti itu untuk menggaungkan angka, $IFSdefault di spasi putih dan itu diharapkan angka, jadi tidak perlu berurusan dengan backslash. Satu-satunya downside dari jawaban ini adalah kebutuhan mengetahui jumlah kolom sebelum eksekusi.
kos
@ cos Anda tidak akan pernah tahu bagaimana file input bisa. Dan meskipun OP hanya menyebutkan angka, itu selalu praktik yang baik untuk mempersiapkan yang buruk. Lihat Bagaimana saya bisa membaca file (aliran data, variabel) baris demi baris (dan / atau bidang-demi-bidang)? untuk penjelasan yang luar biasa.
fedorqui
@ fedorqui Per pernyataan Anda sendiri Saya kira ini tidak ada diskusi; Jika Anda ingin membuat poin dengan asumsi bahwa file input dapat berisi sesuatu selain angka, Anda melewatkan bagian yang mencolok: memeriksa apakah yang dibaca adalah angka. Menambahkan string dan menggunakan echo "[...]"untuk mencetak dengan benar apa yang tidak ingin Anda hasilkan tidak masuk akal.
kos
@kos Anda tentu saja bisa mengatakan echo $vardan while read a b c, itu bekerja di sini. Namun, Anda akan terbiasa menulis dengan cara yang lemah dan suatu hari Anda akan mendapatkan kesalahan aneh saat memproses file yang lebih kompleks. Maka Anda akan melihat mengutip variabel dan menggunakan while IFS= read -r ...lebih aman dan akan berkata "oh yeah fedorqui benar, saya harap saya bisa memeluknya untuk menunjukkan rasa terima kasih!".
fedorqui
3

Menilai dari komentar atas jawaban Anda sendiri, Anda hanya ingin jumlah satu kolom pada satu waktu. Jika demikian, berikut ini adalah cara non-awk untuk melakukannya:

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

di mana Anda akan mengganti 3dengan nomor kolom yang Anda minati.

Trauma Digital
sumber
0

Berikut ini adalah pendekatan skrip Perl satu baris. Ini bergantung pada penggunaan -aflag yang memungkinkan auto-splitting saat ini membaca baris dengan -nflag menjadi array @F. Yang harus kita lakukan adalah beralih pada item-item itu, dan menambahkannya ke indeks masing-masing dalam $sumarray, sehingga secara efektif setiap item array adalah jumlah untuk setiap kolom masing-masing. Akhirnya, kami mencetak hasilnya dalam ENDblok kode.

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

Atau, inilah pendekatan skrip Perl lengkap. Itu bergantung pada pemisahan setiap baris ke dalam array, dan iterasi atas setiap item dalam array yang menambahkan setiap nomor ke kepemilikan masing-masing dalam @sumsarray. Script mencetak setiap baris, lalu menghasilkan laporan untuk setiap kolom. Pencetakan setiap baris dapat dihapus dengan menambahkan #sebelumnyaprintf("%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);

Penggunaannya sederhana chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Sebagai contoh:

$ ./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
Sergiy Kolodyazhnyy
sumber
-2

Solusi sederhana:

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

Ganti saya dengan nomor kolom misalnya kolom1:

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

output adalah:

8
Maythux
sumber
3
Ini hanya membuat Anda satu kolom. Anda tidak memenuhi spesifikasi Anda sendiri.
Oli
Saya tidak menyatakan bahwa saya ingin semua hasil dalam perintah yang sama. ditambah jawaban ini hanya perlu satu loop dan itu sempurna
Maythux
Jadi mengapa downvoting?
Maythux