ฉันจะรวมตัวเลขทั้งหมดในไฟล์ได้อย่างรวดเร็วได้อย่างไร


16

แต่ละบรรทัดประกอบด้วยข้อความและตัวเลขในหนึ่งคอลัมน์ ฉันต้องคำนวณผลรวมของตัวเลขในแต่ละแถว ฉันจะทำสิ่งนั้นได้อย่างไร ขอบคุณ

example.log ประกอบด้วย:

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

คำตอบควรเป็น784


ฉันลองวิธีนี้แล้ว awk '{sum + = $ 1}; END {ตัวอย่างผลรวม} 'example.log แต่ใช้สำหรับตัวเลขในบรรทัดเท่านั้น
แจ็ค

2
มีคำถามเดียวกันเกือบทั้งหมดในStack Overflow : ฉันจะรวมตัวเลขทั้งหมดในไฟล์ได้อย่างรวดเร็วได้อย่างไร . บางทีเวลามีการทำซ้ำข้ามไซต์?
fedorqui

คำตอบ:


18

หากตัวเลือกgrepการสนับสนุนของ-oคุณคุณสามารถลอง:

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

POSIXly:

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

16

ด้วยรุ่นที่ใหม่กว่า (4.x) ของ GNU awk:

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

ด้วยความawkพยายามอื่น ๆ:

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

4
คุณต้องการs+0ในกรณีที่sว่างเปล่ามันจะพิมพ์0แทนที่จะว่างเปล่า
cuonglm

ฉันขออธิบายว่า - มีเพียงกรณีเดียวที่sสามารถว่างเปล่าได้ ถ้าข้อมูลอินพุตไม่มีบรรทัด (เช่นถ้าไม่มีอินพุตเลย ) ในกรณีนั้นมีพฤติกรรมที่เป็นไปได้สองอย่าง 1) ไม่มีอินพุต => ไม่มีเอาต์พุตหรือ 2) ส่งเอาต์พุตบางอย่างเสมอถ้าเพียง 0 ทั้งสองตัวเลือกที่เหมาะสมขึ้นอยู่กับบริบทของแอปพลิเคชัน +0เป็นทางเลือกที่ 2 ที่อยู่) ไปยังที่อยู่ตัวเลือกที่ 1) END {if(s) print s}คุณอาจจะต้องมีการเขียน - ดังนั้นจึงไม่มีเหตุผลที่จะถือว่าตัวเลือกใดตัวเลือกหนึ่ง (สำหรับกรณีมุมนี้ไม่มีข้อมูล) จนกว่าจะถูกระบุโดยคำถาม
Janis

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

2
เราต้องการคำตอบแบบยาว คุณช่วยอธิบายรายละเอียดเกี่ยวกับการทำงานของมันได้ไหม?
slm

2
@slm คำตอบนั้นไม่ได้มากเกินไปน้อยกว่าคำตอบอื่น ๆ ที่นี่และอธิบายด้วยตนเอง นอกจากนี้ยังมีข้อได้เปรียบในการทำงานกับอินพุตเช่นtime=1.4e5sec
Stéphane Chazelas

@ StéphaneChazelas - เห็นด้วย แต่นี่เป็นผู้ใช้ใหม่และเราสนับสนุนให้ผู้ใช้ตอบมากกว่าหนึ่งคำตอบ ข้อความเล็กน้อยอธิบายว่ามันทำงานอย่างไรจะทำให้เป็นคำตอบที่ดีกว่ารหัสเพียง
slm

4
@slm นี้เป็นผู้ใช้ใหม่ที่มีหนึ่งในคำตอบที่ดีที่สุด (จากจุดยืนทางเทคนิค) และเขาได้รับสอง downvotes และความคิดเห็นเชิงลบ ไม่เป็นการต้อนรับที่อบอุ่นมาก
Stéphane Chazelas

1
@TomFenech ไวยากรณ์ POSIX สำหรับ awk ต้องการให้ไอเท็มรูปแบบ / แอ็คชันเหล่านั้นถูกคั่นด้วย ";" หรือ "ขึ้นบรรทัดใหม่" ดังนั้นคุณอาจพบว่าการติดตั้ง awk นั้นล้มเหลวโดยที่ไม่มีสิ่งนี้ ";"
Stéphane Chazelas

7

อีก GNU awkหนึ่ง:

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

perlหนึ่ง:

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

POSIX หนึ่ง:

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

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

คำตอบที่ยอดเยี่ยม แต่ไม่จำเป็นสำหรับsed:awk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
user1717828

@ user1717828: คุณควรใช้ (สั้นกว่าและเข้ากันได้มากกว่า!) -F'='แทน--field-separator =
Olivier Dulac

@OlivierDulac, แปลก, man awkเพียงผู้เดียวของฉันให้-F fsและ--field-separator fs
user1717828

@ user1717828: -F'='หรือทำ-F '='2 วิธี-F fs(fs คือ "=" ในกรณีของคุณ) ฉันเพิ่ม singlequotes เพื่อให้แน่ใจว่า fs สามารถมองเห็นได้อย่างถูกต้อง & ตีความโดย awk ไม่ใช่เชลล์ (มีประโยชน์ถ้า fs คือ ';' เป็นตัวอย่าง)
Olivier Dulac


4

ทุกคนโพสต์awkคำตอบที่ยอดเยี่ยมซึ่งฉันชอบมาก

รูปแบบของ @cuonglm แทนที่grepด้วยsed:

sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
  1. sedแถบทุกอย่างยกเว้นสำหรับตัวเลข
  2. paste -sd+ -คำสั่งร่วมสายทั้งหมดเข้าด้วยกันเป็นเส้นเดียว
  3. การbcประเมินการแสดงออก

3

คุณควรใช้เครื่องคิดเลข

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

ด้วยสี่บรรทัดที่พิมพ์:

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

และอื่น ๆ :

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

... ที่พิมพ์ ...

31
223
241
784

หากความเร็วเป็นสิ่งที่คุณต้องการหลังจากนั้นก็dcเป็นสิ่งที่คุณต้องการ ตามเนื้อผ้ามันเป็นbcคอมไพเลอร์ - และยังคงมีอยู่สำหรับหลาย ๆ ระบบ


ไม่เป็นไปตามการวัดของฉัน : มันขึ้นอยู่กับว่าคุณต้องทำมากแค่ไหนในการสร้างสูตร
glenn jackman

@glennjackman - การวัดของคุณไม่รวมdcอยู่ใกล้เท่าที่ฉันจะบอกได้ คุณกำลังพูดเรื่องอะไร
mikeserv

อย่างไรก็ตามเมื่อเปรียบเทียบลูกเรือเก่ากับลูกเรือใหม่ - เช่นเมื่อคุณเปรียบเทียบperlกับชุดเครื่องมือยูนิกซ์มาตรฐาน - มันไม่สมเหตุสมผลถ้าคุณใช้เครื่องมือ GNU ที่คอมไพล์บน GNU toolchain ทั้งหมดของการขยายตัวที่ลบจะส่งผลกระทบต่อประสิทธิภาพการทำงานของ Perl เป็นยังในทั้งหมดของผู้ที่ GNU รวบรวม utils GNU เศร้า แต่จริง คุณต้องมีชุดเครื่องมือจริงที่เรียบง่ายและสร้างขึ้นมาเพื่อตัดสินความแตกต่างอย่างแม่นยำ เช่นมรดกตกทอด - ชุดเครื่องมือแบบคงที่เชื่อมโยงกับ libs libl ตัวอย่าง - ในแบบที่คุณสามารถบัลลังก์กระบวนทัศน์หนึ่งเครื่องมือ / หนึ่งงานเทียบกับเครื่องมือหนึ่งไปสู่กฎพวกเขาทั้งหมด
mikeserv

3

ผ่าน python3

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

re.findallส่งคืนรายการสตริงซึ่งจะไม่ทำงาน
iruvar

@ 1_CR ใช่ฉันลืมไปแล้ว ตรวจสอบทันที
Avinash Raj

อาจจะsum(int(e) for e in l)เป็น pythonic เพิ่มเติม
cuonglm

3

สารละลายทุบตีบริสุทธิ์ (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.

เวอร์ชั่นสั้น:

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

1
อาจจะ:PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile
mikeserv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.