Setiap baris berisi teks dan angka dalam satu kolom. Saya perlu menghitung jumlah angka di setiap baris. Bagaimana saya bisa melakukan itu? Terima kasih
example.log berisi:
time=31sec
time=192sec
time=18sec
time=543sec
Jawabannya harus 784
Setiap baris berisi teks dan angka dalam satu kolom. Saya perlu menghitung jumlah angka di setiap baris. Bagaimana saya bisa melakukan itu? Terima kasih
example.log berisi:
time=31sec
time=192sec
time=18sec
time=543sec
Jawabannya harus 784
Jawaban:
Dengan versi GNU yang lebih baru (4.x) awk
:
awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'
Dengan awk
percobaan lain:
awk -F '[a-z=]*' '{s+=$2}END{print s}'
s+0
dalam kasus di mana s
kosong, itu akan mencetak 0
bukannya kosong.
s
bisa kosong; jika input data tidak mengandung garis (yaitu jika tidak ada input sama sekali ). Dalam hal ini ada dua perilaku yang mungkin; 1) tidak ada input => tidak ada output, atau 2) selalu mengeluarkan sesuatu, jika hanya 0. Keduanya merupakan opsi yang masuk akal tergantung pada konteks aplikasi. The +0
adalah menangani opsi 2). Untuk mengatasi opsi 1) Anda lebih suka menulis END {if(s) print s}
. - Oleh karena itu tidak masuk akal untuk mengasumsikan salah satu opsi (untuk kasus sudut ini tidak ada data) sampai ditentukan oleh pertanyaan.
awk -F= '{sum+=$2};END{print sum}'
time=1.4e5sec
Satu lagi GNU awk
:
awk -v RS='[0-9]+' '{n+=RT};END{print n}'
Satu perl
:
perl -lne'$n+=$_ for/\d+/g}{print$n'
Yang 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'='
daripada--field-separator =
man awk
hanya memberi -F fs
dan--field-separator fs
-F'='
atau -F '='
ada 2 cara untuk melakukan -F fs
(fs adalah "=" dalam kasus Anda). Saya menambahkan singlequotes untuk memastikan fs benar dilihat & ditafsirkan oleh awk, bukan shell (berguna jika fs adalah ';' misalnya)
Setiap orang telah memposting awk
jawaban yang luar biasa , yang sangat saya sukai.
Variasi untuk @cuonglm diganti grep
dengan sed
:
sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
sed
strip segala sesuatu kecuali untuk nomor.paste -sd+ -
perintah bergabung semua lini bersama-sama sebagai satu barisbc
mengevaluasi ekspresiAnda harus menggunakan kalkulator.
{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null
Dengan empat baris Anda yang mencetak:
time=31
time=223
time=241
time=784
Dan lebih sederhana:
tr times=c ' + p' <infile |dc
... yang mencetak ...
31
223
241
784
Jika kecepatan adalah apa yang Anda cari maka dc
itu yang Anda inginkan. Secara tradisional itu adalah bc
kompiler - dan masih untuk banyak sistem.
dc
saya tahu. Apa yang sedang Anda bicarakan?
perl
terhadap standar unix toolset - benar-benar tidak masuk akal jika Anda menggunakan alat GNU yang dikompilasi di rantai alat GNU. Semua mengasapi yang secara negatif dapat mempengaruhi kinerja Perl juga di semua util GNU yang dikompilasi. Sedih tapi benar. Anda memerlukan toolset nyata, sederhana dibangun, sederhana untuk menilai perbedaan secara akurat. Sebagai contoh, set alat pusaka yang secara statis terhubung dengan musl libs misalnya - dengan cara itu Anda dapat menempatkan paradigma satu-alat / satu-pekerjaan vs satu-alat-untuk-memerintah-semuanya-semuanya.
Melalui python3,
import re
with open(file) as f:
m = f.read()
l = re.findall(r'\d+', m)
print(sum(map(int, l)))
re.findall
mengembalikan daftar string, ini tidak akan berfungsi
sum(int(e) for e in l)
lebih pythonic.
Solusi bash murni (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.
Versi pendek:
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