Đếm tổng của mỗi cột trong một tệp


9

Trong một tệp có số lượng cột khác nhau được phân tách bằng dấu cách '', Cách tính tổng của các cột. Một ví dụ sẽ cho thấy sự cần thiết:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

Sau đó, đầu ra sẽ là:

  • cho cột 1 (1 + 2 + 4 + 1) = 8
  • cho cột 2 là 11
  • cho cột 3 là 7
  • cho cột 4 là 5

Câu trả lời:


12

Sử dụng 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

Việc sử dụng tốt các mảng mặc dù tôi nghĩ rằng nó có thể được đơn giản hóa chỉ bằng cách đếm tổng và in ngay lập tức
Sergiy Kolodyazhnyy

Quả thực đây là câu trả lời tốt nhất ở đây.
kos

5

Sử dụng numsumcho nhiệm vụ đó và tách biệt giữa xử lý dữ liệu và xuất kết quả.

Cài đặt num-utils, chúng tôi cầnnumsum

sudo apt-get install num-utils

Và bắt đầu với

numsum -c <your_file_name>

Thí dụ

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

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

hoặc với định dạng mong muốn của bạn:

$ 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

từ man numsum

-c      Print out the sum of each column.

ví dụ từ 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

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

Bạn có thể có thể nói (( col1 += a )), vv Ngoài ra, echo "..."an toàn hơn, cũng nhưwhile IFS= read -r ...
fedorqui

@fedorqui echoan toàn khi được sử dụng theo cách đó để lặp lại các số, $IFSmặc định ở khoảng trắng và chúng được dự kiến ​​là số, do đó không cần phải xử lý dấu gạch chéo ngược. Nhược điểm duy nhất của câu trả lời này là cần biết số lượng cột trước khi thực hiện.
kos

@kos bạn không bao giờ có thể biết làm thế nào một tập tin đầu vào có thể. Và mặc dù OP chỉ đề cập đến những con số, nó luôn luôn là thực hành tốt để chuẩn bị cho điều tồi tệ hơn. Xem Làm cách nào tôi có thể đọc một tệp (luồng dữ liệu, biến) theo từng dòng (và / hoặc từng trường)? cho một lời giải thích tuyệt vời.
fedorqui

@fedorqui Mỗi tuyên bố của riêng bạn Tôi nghĩ rằng điều này đã được thảo luận; Nếu bạn muốn tạo điểm giả định rằng tệp đầu vào có thể chứa thứ gì đó không phải là số, bạn đang thiếu phần trắng trợn: kiểm tra xem những gì được đọc có phải là một số không. Thêm chuỗi và sử dụng echo "[...]"để in chính xác những gì bạn không muốn xuất không có ý nghĩa.
kos

@kos Tất nhiên bạn có thể nói echo $varwhile read a b c, nó hoạt động ở đây. Tuy nhiên, bạn sẽ quen với việc viết nó theo cách yếu và một ngày nào đó bạn sẽ gặp phải những lỗi lạ trong khi xử lý một tệp phức tạp hơn. Sau đó, bạn sẽ nhận thấy trích dẫn các biến và sử dụng while IFS= read -r ...là an toàn hơn và sẽ nói "oh yeah fedorqui đã đúng, tôi hy vọng tôi có thể có anh ấy để ôm anh ấy để thể hiện lòng biết ơn!".
fedorqui

3

Đánh giá bằng các bình luận cho câu trả lời của riêng bạn, bạn chỉ muốn tổng của một cột tại một thời điểm. Nếu vậy, đây là một cách không hay để làm điều đó:

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

nơi bạn sẽ thay thế 3bằng số cột bạn quan tâm.


0

Đây là một cách tiếp cận kịch bản Perl một lớp. Điều này phụ thuộc vào việc sử dụng -acờ cho phép tự động phân tách dòng đang đọc với -ncờ thành mảng @F. Tất cả những gì chúng ta phải làm là lặp lại các mục đó và thêm chúng vào chỉ mục tương ứng của chúng trong $summảng, do đó, hiệu quả của từng mục mảng là tổng cho mỗi cột tương ứng. Cuối cùng, chúng tôi in kết quả trong ENDkhối mã.

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

Ngoài ra, đây là một cách tiếp cận kịch bản Perl đầy đủ. Nó dựa vào việc chia từng dòng thành mảng và lặp lại qua từng mục trong mảng đó thêm từng số vào sở hữu tương ứng của chúng trong @sumsmảng. Kịch bản in ra từng dòng, sau đó tạo báo cáo cho từng cột. In từng dòng có thể được loại bỏ bằng cách thêm #trướcprintf("%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);

Cách sử dụng rất đơn giản chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Ví dụ:

$ ./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

Một giải pháp đơn giản:

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

Thay thế i bằng số cột ví dụ cột1:

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

đầu ra là:

8

3
Điều này chỉ giúp bạn có một cột. Bạn không đáp ứng đặc điểm kỹ thuật của riêng bạn.
Oli

Tôi đã không nói rằng tôi muốn tất cả các kết quả trong cùng một lệnh. cộng với câu trả lời này chỉ cần một vòng lặp và nó thật hoàn hảo
Maythux

Vậy tại sao lại hạ thấp?
Maythux
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.