Làm cách nào tôi có thể tổng hợp số trên các dòng trong một tệp


24

Tôi có một tập tin trông như thế này:

1
3
4
1
4
3
1
2

Làm thế nào tôi có thể tìm thấy tổng số này (tức là 1 + 3 + 4 + 1 + 4 + 3 + 1 + 2 = 19)?


1
Đối với ngữ cảnh, tôi đang đếm số lượng huy hiệu tôi có trên Hỏi Ubuntu từ API trao đổi ngăn xếp.
Tim

Vớicat badges.json | grep -o '"award_count":[0-9],"rank":"gold"' | grep -o [0-9]
Tim

Mặc dù bây giờ tôi nhận ra API có một badge_countphương thức.
Tim

Nếu bạn đang đếm các huy hiệu từ API, ngôn ngữ bạn đang sử dụng để truy vấn API không thể làm điều này (python, javascript)?
Braiam

Câu trả lời:


42

bcvới một chút trợ giúp pasteđể có được các dòng trong một cái duy nhất với +dấu phân cách:

paste -sd+ file.txt | bc

Để sử dụng đầu ra của grep(hoặc bất kỳ lệnh nào khác) thay vì tệp tĩnh, hãy chuyển grepSTDOUT của STDIN sang paste:

grep .... | paste -sd+ | bc

Thí dụ:

% cat file.txt            
1
3
4
1
4
3
1
2

% paste -sd+ file.txt | bc
19

% grep . file.txt | paste -sd+ | bc
19

Nếu bạn phải sử dụng bash, thì bạn có thể sử dụng một mảng để lưu nội dung tệp và sau đó lặp lại các phần tử hoặc bạn có thể đọc từng dòng tệp và thực hiện tổng cho từng dòng, cách tiếp cận thứ hai sẽ hiệu quả hơn:

$ time { nums=$(<file.txt); for i in ${nums[@]}; do (( sum+=i )); done; echo $sum ;}
19

real    0m0.002s
user    0m0.000s
sys 0m0.000s

$ time { while read i; do (( sum+=i )); done <file.txt; echo $sum ;}
19

real    0m0.000s
user    0m0.000s
sys 0m0.000s

Hừm, đẹp quá. Xin lỗi để thay đổi câu hỏi: tôi có thể sửa đổi điều này để chấp nhận đầu ra grep không (hoặc biến nó thành một dòng như thế cat file.txt | bcnào?
Tim

@Tim Kiểm tra các chỉnh sửa của tôi
heemayl

Ta, thật đơn giản!
Tim

2
cách stdin không làm việc cho tôi cho đến khi tôi phát hiện ra trong một câu trả lời khác mà tôi phải sử dụng paste -sd+ -. Hãy sửa đổi điều đó.
Xerus

19

Bạn cũng có thể sử dụng awk. Để đếm tổng số dòng trong tệp * .txt có chứa từ "xin chào":

grep -ch 'hello' *.txt | awk '{n += $1}; END{print n}'

Để đơn giản là tổng các số trong một tệp:

awk '{n += $1}; END{print n}' file.txt

Nhưng nếu dòng đó có giá trị "4" thì nó sẽ không được tính 4. Nó sẽ được tính 1.
Tim

Không, nó sẽ được tính 4.
CrazyApe84

Tôi muốn tổng số các số trong một tập tin. Điều này có làm điều đó?
Tim

Tôi nghĩ bạn đã thay đổi câu hỏi của bạn thành đầu ra của grep. Tôi đã đưa ra một số giả định. Tôi sẽ thêm cách đơn giản để tổng hợp các giá trị trong một tệp.
CrazyApe84

2
Vâng. Đó thực sự là câu trả lời giống như của heemayl, nhưng thay vì dán và bc, nó sử dụng awk, điều này cuối cùng mang lại sự linh hoạt hơn rất nhiều. Tuy nhiên, câu trả lời của anh ấy là tốt và anh ấy là người đầu tiên vì vậy anh ấy xứng đáng với phiếu bầu của bạn!
CrazyApe84

7

Sử dụng numsumtừ gói num-utils!

(Bạn có thể cần phải sudo apt-get install num-utils)

Lệnh numsumthực hiện đúng những gì bạn cần theo mặc định;

$ numsum file.txt 
19

Đọc các số kiểm tra từng dòng từ stdin:

$ printf '
1 
3
4
1
4
3
1
2' | numsum
19

Hoặc đọc từ một dòng:

$ printf '1 3 4 1 4 3 1 2' | numsum -r
19


Thêm tiện ích

Gói chứa một số tiện ích khác để xử lý số đáng được biết đến nhiều hơn:

numaverage   - find the average of the numbers, or the mode or median
numbound     - find minimum of maximum of all lines
numgrep      - to find numbers matching ranges or sets
numinterval  - roughly like the first derivative
numnormalize - normalize numbers to an interval, like 0-1
numrandom    - random numbers from ranges or sets, eg odd.  
numrange     - similar to seq
numround     - round numbers up, down or to nearest

và một lệnh máy tính tổng quát hơn numprocess,
áp dụng một biểu thức từ dòng lệnh đến các số trên các dòng đầu vào.


1

Bạn có thể sử dụng awk, một ứng dụng linux gốc hữu ích để quét và xử lý các tệp với một mẫu trên mỗi dòng. Đối với câu hỏi của bạn, điều này sẽ tạo ra những gì bạn muốn:

awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }' file.txt

Ống cũng được chấp nhận:

cat file.txt | awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }'

Không cần một BEGIN{}khối, xem câu trả lời của CrazyApe84 .
terdon

Nó là dư thừa cho vấn đề này nhưng tôi thích đưa nó vào mục đích giáo huấn.
gwarah

Nhưng nó dạy cái gì? Nó là dư thừa cho mọi vấn đề, awkkhông phải là C, bạn không cần phải đặt biến trước khi sử dụng nó. Hãy thử awk 'BEGIN{print c+=1}'.
terdon

BEGIN {}khối không được thiết kế chỉ để khởi tạo các biến. Nó tham gia vào đặc điểm kỹ thuật thiết kế. Vì vậy, về một số vấn đề có thể cần thiết.
gwarah

0

Đây là một cách sử dụng bashkịch bản khá đơn giản .

SUM=0; for line in `cat file.txt`; do SUM=$((SUM + line)); done

Điều này là đơn giản hơn nhiều và bộ công cụ tối giản hơn so với giải pháp hiện tại.
Det

0

Giải pháp Perl:

$ perl -lnae '$c+=$_;END{print $c}' input.txt                                                                            
19

Ở trên có thể tổng hợp tất cả các số trên nhiều tệp:

$ perl -lnae '$c+=$_;END{print $c}' input.txt input2.txt                                                                 
34

Đối với nhiều tệp được cung cấp trên dòng lệnh nơi chúng tôi muốn xem tổng số trong tệp riêng lẻ, chúng tôi có thể thực hiện việc này:

$ perl -lnae '$c+=$_;if(eof){printf("%d %s\n",$c,$ARGV);$c=0}' input.txt input2.txt                                      
19 input.txt
15 input2.txt

0

Đơn giản -

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

cộng các số và cung cấp cho bạn tổng số.


0

Một cách tiếp cận đơn giản là sử dụng tính năng tích hợp trong vỏ của bạn:

SUM=0; while read N; do SUM=$((SUM+N)); done </path/to/file
echo $SUM

Điều này đọc tệp của bạn theo chiều dọc, tổng hợp và in kết quả.

Nếu bạn muốn sử dụng một đường ống và chỉ sử dụng hàng thứ 1, nó hoạt động như thế này:

SUM=0
your_command | while read -r LINE; do for N in $LINE; do break; done; SUM=$((SUM+N)); done
echo $SUM

Lấy phần tử đầu tiên được thực hiện như thế này:

LIST="foo bar baz"
for OBJ in $LIST; do break; done
echo $OBJ

foo
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.