Mỗi dòng chứa văn bản và số trong một cột. Tôi cần tính tổng của các số trong mỗi hàng. Làm thế nào tôi có thể làm điều đó? Cám ơn
example.log chứa:
time=31sec
time=192sec
time=18sec
time=543sec
Câu trả lời phải là 784
Mỗi dòng chứa văn bản và số trong một cột. Tôi cần tính tổng của các số trong mỗi hàng. Làm thế nào tôi có thể làm điều đó? Cám ơn
example.log chứa:
time=31sec
time=192sec
time=18sec
time=543sec
Câu trả lời phải là 784
Câu trả lời:
Với phiên bản mới hơn (4.x) của GNU awk
:
awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'
Với những awk
thử khác:
awk -F '[a-z=]*' '{s+=$2}END{print s}'
s+0
trong trường hợp s
trống, nó sẽ in 0
thay vì trống.
s
có thể để trống; nếu dữ liệu đầu vào không chứa dòng nào (tức là nếu không có đầu vào nào cả ). Trong trường hợp đó có hai hành vi có thể; 1) không có đầu vào => không có đầu ra hoặc 2) luôn xuất ra thứ gì đó, nếu chỉ 0. Cả hai đều là các tùy chọn hợp lý tùy thuộc vào ngữ cảnh ứng dụng. Đây +0
là địa chỉ tùy chọn 2). Để giải quyết tùy chọn 1) bạn muốn viết END {if(s) print s}
. - Do đó, sẽ không có ý nghĩa gì khi giả sử một trong hai tùy chọn (đối với trường hợp góc không có dữ liệu này) cho đến khi được chỉ định bởi câu hỏi.
awk -F= '{sum+=$2};END{print sum}'
time=1.4e5sec
Một GNU khác awk
:
awk -v RS='[0-9]+' '{n+=RT};END{print n}'
Một perl
một:
perl -lne'$n+=$_ for/\d+/g}{print$n'
Một POSIX:
tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}'
sed
:awk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
-F'='
thay vì--field-separator =
man awk
chỉ cho -F fs
và--field-separator fs
-F'='
hoặc -F '='
là 2 cách thực hiện -F fs
(fs là "=" trong trường hợp của bạn). Tôi đã thêm các câu đơn để đảm bảo fs được nhìn thấy và giải thích chính xác bởi awk, chứ không phải shell (ví dụ nếu fs là ';' chẳng hạn)
Mọi người đã đăng awk
câu trả lời tuyệt vời , mà tôi rất thích.
Một biến thể để @cuonglm thay thế grep
bằng sed
:
sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
sed
dải tất cả mọi thứ trừ các con số.paste -sd+ -
lệnh tham gia tất cả các dòng với nhau như một dòng duy nhấtbc
đánh giá biểu thứcBạn nên sử dụng một máy tính.
{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null
Với bốn dòng của bạn in:
time=31
time=223
time=241
time=784
Và đơn giản hơn:
tr times=c ' + p' <infile |dc
... mà in ...
31
223
241
784
Nếu tốc độ là thứ bạn đang theo đuổi thì đó dc
là thứ bạn muốn. Theo truyền thống, nó là bc
trình biên dịch - và vẫn dành cho nhiều hệ thống.
dc
gần như tôi có thể nói. Bạn đang nói về cái gì vậy?
perl
v bộ công cụ unix tiêu chuẩn - thực sự không có ý nghĩa gì nếu bạn sử dụng các công cụ GNU được biên dịch trên chuỗi công cụ GNU. Tất cả sự phình to có thể ảnh hưởng tiêu cực đến hiệu suất của Perl cũng nằm trong tất cả các tiện ích GNU được biên dịch bởi GNU. Đáng buồn nhưng là sự thật. Bạn cần một bộ công cụ thực sự, được xây dựng đơn giản, đơn giản để đánh giá chính xác sự khác biệt. Ví dụ như một bộ công cụ gia truyền được liên kết tĩnh với các lib musl - theo cách đó bạn có thể điều chỉnh mô hình một công cụ / một công việc so với mô hình một công cụ để thống trị tất cả một.
Qua python3,
import re
with open(file) as f:
m = f.read()
l = re.findall(r'\d+', m)
print(sum(map(int, l)))
re.findall
trả về một danh sách các chuỗi, điều này sẽ không hoạt động
sum(int(e) for e in l)
là nhiều pythonic.
Dung dịch bash tinh khiết (Bash 3+):
while IFS= read -r line; do # While it reads a line:
if [[ "$line" =~ [0-9]+ ]]; then # If the line contains numbers:
((counter+=BASH_REMATCH[0])) # Add the current number to counter
fi # End if.
done # End loop.
echo "Total number: $counter" # Print the number.
unset counter # Reset counter to 0.
Phiên bản ngắn:
while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0
PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile