Bir dosyadaki tüm sayıları nasıl hızlı bir şekilde toplayabilirim?


16

Her satır bir sütunda metin ve sayılar içerir. Her satırdaki sayıların toplamını hesaplamam gerekiyor. Bunu nasıl yapabilirim? Teşekkür

example.log şunları içerir:

time=31sec
time=192sec
time=18sec
time=543sec

Cevap 784 olmalı


Bu yöntemi denedim awk '{sum + = $ 1}; END {print sum} 'example.log ancak bu yalnızca satırdaki sayılar içindir
Jack,

2
Stack Overflow'da neredeyse aynı soru var : Bir dosyadaki tüm sayıları nasıl hızlı bir şekilde toplayabilirim? . Belki siteler arası kopyalar alma zamanı?
fedorqui

Yanıtlar:


18

Senin Eğer grepdestek -oseçeneği, deneyebilirsin:

$ grep -o '[[:digit:]]*' file | paste -sd+ - | bc
784

POSIXly:

$ printf %d\\n "$(( $(tr -cs 0-9 '[\n*]' <file | paste -sd+ -) ))"
784

16

GNU'nun daha yeni bir sürümü (4.x) ile awk:

awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'

Diğer awks ile deneyin:

awk -F '[a-z=]*' '{s+=$2}END{print s}'

4
İhtiyacınız s+0halinde sboştur, bunun yazdırılır 0yerine boş bir.
cuonglm

Bunu açıklayayım. - sBoş olabilecek tek bir durum var ; giriş verileri satır içermiyorsa (yani hiç giriş yoksa ). Bu durumda iki davranış mümkündür; 1) giriş yok = çıkış yok veya 2) yalnızca 0 ise her zaman bir şeyler çıkarır. Her ikisi de uygulama içeriğine bağlı olarak mantıklı seçeneklerdir. +0) 2. seçeneği ele alıyor. Seçenek 1'e hitap etmek için yazmak istersiniz END {if(s) print s}. - Bu nedenle, soru tarafından belirtilene kadar her iki seçeneği de kabul etmek mantıklı değildir.
Janis

10
awk -F= '{sum+=$2};END{print sum}'

2
Uzun form cevaplarını tercih ediyoruz. Bunun nasıl işlediğini açıklayabilir misiniz?
slm

2
@slm, bu cevap, buradaki diğer cevaplardan daha fazla veya daha az ayrıntılı değildir ve açıklayıcıdır. Ayrıca giriş gibi çalışma avantajına sahiptirtime=1.4e5sec
Stéphane Chazelas

@ StéphaneChazelas - kabul etti, ancak bu yeni bir kullanıcı ve kullanıcıları tek satırdan fazla cevap vermeye teşvik ediyoruz. Nasıl çalıştığını açıklayan biraz metin, onu koddan çok daha güçlü bir cevap haline getirecektir.
slm

4
@slm, bu en iyi cevaplardan birine (teknik açıdan bakıldığında) sahip yeni bir kullanıcı ve iki downvotes ve olumsuz bir yorum alıyor. Çok sıcak bir karşılama değil.
Stéphane Chazelas

1
@TomFenech, awk için POSIX sözdizimi, bu desen / eylem öğelerinin ";" veya "satırsonu", böylece ";" olmadan başarısız olduğu yerde garip uygulamalar bulabilirsiniz.
Stéphane Chazelas

7

Başka bir GNU awkolanı:

awk -v RS='[0-9]+' '{n+=RT};END{print n}'

Bir perl:

perl -lne'$n+=$_ for/\d+/g}{print$n'

POSIX olanı:

tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc

6
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}'

Müthiş cevap, ancak gerek yok sed:awk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
user1717828

@ user1717828: Bunun yerine (daha uyumlu daha kısa ve!) kullanmalıdır -F'='yerine--field-separator =
Olivier Dulac

@OlivierDulac, garip, benim man awktek verir -F fsve--field-separator fs
user1717828

@ user1717828: -F'='veya -F '='bunu yapmanın 2 yolu vardır -F fs(fs sizin durumunuzda "="). Tek tırnakları fs'nin kabuk tarafından değil, awk tarafından düzgün bir şekilde görülebilmesini ve yorumlanmasını sağlamak için ekledim (örneğin fs ';' ise faydalıdır)
Olivier Dulac

4

Bunu deneyebilirsiniz:

awk -F"[^0-9]+" '{ sum += $2 } END { print sum+0; }' file

4

Herkes awkçok sevdiğim harika cevaplar gönderdi .

Bir varyasyon değiştirilmesi @cuonglm için grepolan sed:

sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
  1. sedSayılar hariç her şeyi şeritler.
  2. paste -sd+ -Komut tek bir satır olarak hep birlikte hatlarını katılır
  3. bcifade değerlendirir

3

Bir hesap makinesi kullanmalısınız.

{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null

Dört satır yazdırır:

time=31
time=223
time=241
time=784

Ve daha basit:

tr times=c '    + p' <infile |dc

... hangi baskı ...

31
223
241
784

Eğer hız peşinde olduğun şeyse dc, istediğin şey budur. Geleneksel olarak bcderleyici idi ve hala birçok sistem için.


Ölçümlerime göre değil : formülü oluşturmak için ne kadar iş yapmanız gerektiğine bağlıdır
glenn jackman

@glennjackman - ölçümleriniz dcsöyleyebildiğim kadar yakın değil . Neden bahsediyorsun?
mikeserv

Bu arada, eski mürettebatı yeni mürettebatla karşılaştırırken - örneğin perlstandart unix araç setini karşılaştırırken - bir GNU araç zincirinde derlenmiş GNU araçlarını kullanmak gerçekten mantıklı değil. Olumsuz Perl performansını etkileyebilir kabartmak tümü olduğu da içinde tüm bu GNU-derlenmiş GNU Araçlarının. Acı ama gerçek. Farkı doğru bir şekilde değerlendirmek için gerçek, basit, basit bir araç setine ihtiyacınız var. Örneğin müslüman kütüphanelerine statik olarak bağlı bir yadigar-araç seti gibi - bu şekilde tek-araç / tek-iş paradigmasını, tek-araç-kural-hepsini-hepsini karşılaştırırsınız.
mikeserv

3

Python3 ile,

import re
with open(file) as f:
    m = f.read()
    l = re.findall(r'\d+', m)
    print(sum(map(int, l)))

re.findallbir dize listesi döndürür, bu işe yaramaz
iruvar

@ 1_CR ya, bunu unutuyorum. Şimdi kontrol et.
Avinash Raj

Belki sum(int(e) for e in l)daha pitoniktir.
cuonglm

3

Saf bash çözeltisi (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.

Kısa versiyon:

while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0

1
Belki de:PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile
mikeserv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.