Perintah Shell untuk menjumlahkan bilangan bulat, satu per baris?

867

Saya mencari perintah yang akan menerima (sebagai input) beberapa baris teks, setiap baris berisi bilangan bulat tunggal, dan menampilkan jumlah bilangan bulat ini.

Sebagai sedikit latar belakang, saya memiliki file log yang mencakup pengukuran waktu. Melalui grepping untuk baris yang relevan dan sedikit sedmemformat ulang saya bisa daftar semua timing dalam file itu. Saya ingin menghitung totalnya. Saya dapat menyalurkan output antara ini ke perintah apa saja untuk melakukan penjumlahan akhir. Saya selalu menggunakan exprdi masa lalu, tetapi kecuali itu berjalan dalam mode RPN saya tidak berpikir itu akan mengatasi ini (dan bahkan kemudian itu akan sulit).

Bagaimana saya bisa mendapatkan penjumlahan bilangan bulat?

Andrzej Doyle
sumber
2
Ini sangat mirip dengan pertanyaan yang saya ajukan beberapa waktu lalu: stackoverflow.com/questions/295781/…
An̲̳̳drew
5
Saya sangat suka pertanyaan ini karena ada banyak kemungkinan jawaban yang benar (atau setidaknya berfungsi).
Francisco Canedo
Pertanyaan ini terasa seperti masalah untuk kode golf. codegolf.stackexchange.com :)
Gordon Bean

Jawaban:

1322

Sedikit canggung harus melakukannya?

awk '{s+=$1} END {print s}' mydatafile

Catatan: beberapa versi awk memiliki beberapa perilaku aneh jika Anda akan menambahkan sesuatu yang melebihi 2 ^ 31 (2147483647). Lihat komentar untuk latar belakang lebih lanjut. Satu saran adalah menggunakan printfdaripada print:

awk '{s+=$1} END {printf "%.0f", s}' mydatafile
Paul Dixon
sumber
7
Ada banyak cinta aneh di ruangan ini! Saya suka bagaimana skrip sederhana seperti ini dapat dimodifikasi untuk menambah kolom data kedua hanya dengan mengubah $ 1 menjadi $ 2
Paul Dixon
2
Tidak ada batasan praktis, karena akan memproses input sebagai aliran. Jadi, jika ia bisa menangani file garis X, Anda bisa yakin itu bisa menangani X +1.
Paul Dixon
4
Saya pernah menulis pemroses milis yang belum sempurna dengan skrip awk dijalankan melalui utilitas liburan. Waktu yang baik :)
LS
2
hanya menggunakan ini untuk: hitung skrip halaman semua dokumen:ls $@ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk '{s+=$2} END {print s}'
domba terbang
8
Hati-hati, itu tidak akan bekerja dengan angka lebih besar dari 2147483647 (yaitu, 2 ^ 31), itu karena awk menggunakan representasi integer yang ditandatangani 32 bit. Gunakan awk '{s+=$1} END {printf "%.0f", s}' mydatafilesebagai gantinya.
Giancarlo Sportelli
665

Rekatkan biasanya menggabungkan baris beberapa file, tetapi juga dapat digunakan untuk mengubah setiap baris file menjadi satu baris. Bendera pembatas memungkinkan Anda untuk melewatkan persamaan tipe x + x ke bc.

paste -s -d+ infile | bc

Atau, saat pemipaan dari stdin,

<commands> | paste -s -d+ - | bc
radoulov
sumber
1
Sangat bagus! Saya akan meletakkan spasi sebelum tanda "+", hanya untuk membantu saya menguraikannya dengan lebih baik, tetapi itu sangat berguna untuk menyalurkan beberapa nomor memori melalui paste & kemudian bc.
Michael H.
73
Jauh lebih mudah diingat dan diketik daripada solusi awk. Juga, perhatikan bahwa pastedapat menggunakan tanda hubung -sebagai nama file - yang akan memungkinkan Anda untuk menyalurkan angka-angka dari output perintah ke dalam output standar pasta tanpa perlu membuat file terlebih dahulu:<commands> | paste -sd+ - | bc
George
19
Saya punya file dengan 100 juta angka. Perintah awk membutuhkan 21 detik; perintah tempel memakan waktu 41 detik. Tapi tetap menyenangkan bertemu 'rekatkan'!
Abhi
4
@Abhi: Menarik: DIKira saya perlu 20-an untuk mencari tahu perintah awk sehingga itu keluar meskipun sampai saya mencoba 100 juta dan satu nomor: D
Mark K Cowan
6
@ George Anda dapat mengabaikannya -. (Ini berguna jika Anda ingin menggabungkan file dengan stdin).
Alois Mahdal
128

Versi satu-baris dalam Python:

$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"
dF.
sumber
Di atas satu-liner tidak berfungsi untuk file di sys.argv [], tetapi yang satu itu stackoverflow.com/questions/450799/...
jfs
Benar-penulis mengatakan dia akan menyalurkan output dari skrip lain ke dalam perintah dan saya mencoba membuatnya sesingkat mungkin :)
dF.
39
Versi yang lebih pendek akanpython -c"import sys; print(sum(map(int, sys.stdin)))"
1718 jfs
4
Saya suka jawaban ini karena mudah dibaca dan fleksibel. Saya membutuhkan ukuran rata-rata file yang lebih kecil dari 10Mb dalam kumpulan direktori dan memodifikasinya sebagai berikut:find . -name '*.epub' -exec stat -c %s '{}' \; | python -c "import sys; nums = [int(n) for n in sys.stdin if int(n) < 10000000]; print(sum(nums)/len(nums))"
Paul Whipp
1
Anda juga dapat menyaring angka-angka non jika Anda memiliki beberapa teks yang dicampur:import sys; print(sum(int(''.join(c for c in l if c.isdigit())) for l in sys.stdin))
Granitosaurus
91

Saya akan menaruh PERINGATAN besar pada solusi yang disetujui secara umum:

awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!

itu karena dalam bentuk ini awk menggunakan representasi integer bertanda 32 bit: ia akan melimpah untuk jumlah yang melebihi 2147483647 (yaitu, 2 ^ 31).

Jawaban yang lebih umum (untuk menjumlahkan bilangan bulat) adalah:

awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD
Giancarlo Sportelli
sumber
Mengapa printf () membantu di sini? Overflow int akan terjadi sebelumnya karena kode penjumlahannya sama.
Robert Klemme
9
Karena masalahnya sebenarnya dalam fungsi "cetak". Awk menggunakan integer 64 bit, tetapi untuk beberapa alasan cetak tidak meningkatkannya menjadi 32 bit.
Giancarlo Sportelli
4
Bug cetak tampaknya diperbaiki, setidaknya untuk awk 4.0.1 & bash 4.3.11, kecuali saya salah: echo -e "2147483647 \n 100" |awk '{s+=$1}END{print s}'shows2147483747
Xen2050
4
Menggunakan pelampung hanya menimbulkan masalah baru: echo 999999999999999999 | awk '{s+=$1} END {printf "%.0f\n", s}'menghasilkan1000000000000000000
Patrick
1
Bukankah seharusnya hanya menggunakan "% ld" pada sistem 64bit bekerja untuk tidak memiliki printf truncate ke 32bit? Seperti yang ditunjukkan @Patrick, mengapung bukan ide yang bagus di sini.
yerforkferchips
78

Pesta polos:

$ cat numbers.txt 
1
2
3
4
5
6
7
8
9
10
$ sum=0; while read num; do ((sum += num)); done < numbers.txt; echo $sum
55
Giacomo
sumber
2
Liner satu yang lebih kecil: stackoverflow.com/questions/450799/…
Khaja Minhajuddin
@ rjack, di mana numdidefinisikan? Saya percaya entah bagaimana itu terhubung ke < numbers.txtekspresi, tetapi tidak jelas caranya.
Atcold
66
dc -f infile -e '[+z1<r]srz1<rp'

Perhatikan bahwa angka negatif yang diawali dengan tanda minus harus diterjemahkan untuk dc, karena menggunakan _awalan daripada -awalan untuk itu. Misalnya melalui tr '-' '_' | dc -f- -e '...'.

Sunting: Karena jawaban ini mendapatkan begitu banyak suara "untuk ketidakjelasan", berikut adalah penjelasan terperinci:

Ekspresi [+z1<r]srz1<rp melakukan hal berikut :

[   interpret everything to the next ] as a string
  +   push two values off the stack, add them and push the result
  z   push the current stack depth
  1   push one
  <r  pop two values and execute register r if the original top-of-stack (1)
      is smaller
]   end of the string, will push the whole thing to the stack
sr  pop a value (the string above) and store it in register r
z   push the current stack depth again
1   push 1
<r  pop two values and execute register r if the original top-of-stack (1)
    is smaller
p   print the current top-of-stack

Sebagai pseudo-code:

  1. Tentukan "add_top_of_stack" sebagai:
    1. Hapus dua nilai teratas dari tumpukan dan tambahkan hasilnya kembali
    2. Jika tumpukan memiliki dua atau lebih nilai, jalankan "add_top_of_stack" secara rekursif
  2. Jika tumpukan memiliki dua atau lebih nilai, jalankan "add_top_of_stack"
  3. Cetak hasilnya, sekarang satu-satunya item yang tersisa di tumpukan

Untuk benar-benar memahami kesederhanaan dan kekuatan dc, berikut ini adalah skrip Python yang berfungsi yang mengimplementasikan beberapa perintah dari dcdan mengeksekusi versi Python dari perintah di atas:

### Implement some commands from dc
registers = {'r': None}
stack = []
def add():
    stack.append(stack.pop() + stack.pop())
def z():
    stack.append(len(stack))
def less(reg):
    if stack.pop() < stack.pop():
        registers[reg]()
def store(reg):
    registers[reg] = stack.pop()
def p():
    print stack[-1]

### Python version of the dc command above

# The equivalent to -f: read a file and push every line to the stack
import fileinput
for line in fileinput.input():
    stack.append(int(line.strip()))

def cmd():
    add()
    z()
    stack.append(1)
    less('r')

stack.append(cmd)
store('r')
z()
stack.append(1)
less('r')
p()
André Laszlo
sumber
2
dc hanyalah alat pilihan untuk digunakan. Tapi saya akan melakukannya dengan ops stack sedikit kurang. Diasumsikan bahwa semua garis benar-benar mengandung nomor: (echo "0"; sed 's/$/ +/' inp; echo 'pq')|dc.
ikrabbe
5
Algoritma secara online: dc -e '0 0 [+?z1<m]dsmxp'. Jadi kami tidak menyimpan semua angka pada tumpukan sebelum memproses tetapi membaca dan memprosesnya satu per satu (lebih tepatnya, baris demi baris, karena satu baris dapat berisi beberapa angka). Perhatikan bahwa baris kosong dapat mengakhiri urutan input.
ruvim
@ Ikrabbe itu bagus. Ini sebenarnya dapat dipersingkat dengan satu karakter lagi: ruang dalam sedsubstitusi dapat dihilangkan, karena dc tidak peduli tentang ruang antara argumen dan operator. (echo "0"; sed 's/$/+/' inputFile; echo 'pq')|dc
WhiteHotLoveTiger
58

Dengan jq :

seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
banyan
sumber
7
Saya suka ini karena saya kira begitu jelas dan singkat sehingga saya mungkin benar-benar dapat mengingatnya.
Alfe
46

Pesta murni dan pendek.

f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))
Daniel
sumber
9
Ini adalah solusi terbaik karena tidak membuat subproses apa pun jika Anda mengganti baris pertama dengan f=$(<numbers.txt).
loentar
1
cara mendapatkan masukan dari stdin? suka dari pipa?
njzk2
@ njzk2 Jika Anda memasukkan f=$(cat); echo $(( ${f//$'\n'/+} ))skrip, maka Anda dapat menyalurkan apa saja ke skrip tersebut atau menjalankannya tanpa argumen untuk input stdin interaktif (diakhiri dengan Control-D).
mklement0
5
@lloentar Ini <numbers.txtmerupakan peningkatan, tetapi, secara keseluruhan, solusi ini hanya efisien untuk file input kecil; misalnya, dengan file 1.000 baris input, awksolusi yang diterima sekitar 20 kali lebih cepat pada mesin saya - dan juga mengkonsumsi lebih sedikit memori, karena file tidak dibaca sekaligus.
mklement0
2
Saya hampir kehilangan harapan ketika saya mencapai yang ini. Bash murni!
Omer Akhter
37
perl -lne '$x += $_; END { print $x; }' < infile.txt
j_random_hacker
sumber
4
Dan saya menambahkannya kembali: "-l" memastikan bahwa keluaran diakhiri dengan LF karena backticks shell `` dan sebagian besar program mengharapkan, dan "<" menunjukkan perintah ini dapat digunakan dalam saluran pipa.
j_random_hacker
Kamu benar. Sebagai alasan: Setiap karakter dalam Perl one-liners membutuhkan kerja mental untuk saya, oleh karena itu saya lebih suka untuk mengupas karakter sebanyak mungkin. Kebiasaan itu berbahaya dalam kasus ini.
jfs
2
Salah satu dari beberapa solusi yang tidak memuat semuanya ke dalam RAM.
Erik Aronesty
28

Lima belas sen saya:

$ cat file.txt | xargs  | sed -e 's/\ /+/g' | bc

Contoh:

$ cat text
1
2
3
3
4
5
6
78
9
0
1
2
3
4
576
7
4444
$ cat text | xargs  | sed -e 's/\ /+/g' | bc 
5148
dunia yang tidak bersalah
sumber
Input saya dapat berisi baris kosong, jadi saya menggunakan apa yang Anda poskan di sini plus a grep -v '^$'. Terima kasih!
James Oravec
Wow!! jawaban anda sungguh luar biasa! favorit pribadi saya dari semua yang ada di tapak
thahgr
Suka ini dan +1 untuk saluran pipa. Solusi yang sangat sederhana dan mudah bagi saya
Gelin Luo
24

Saya sudah melakukan patokan cepat pada jawaban yang ada

  • hanya menggunakan alat standar (maaf untuk hal-hal seperti luaatau rocket),
  • adalah one-liners nyata,
  • mampu menambahkan angka dalam jumlah besar (100 juta), dan
  • cepat (saya mengabaikan yang membutuhkan waktu lebih dari satu menit).

Saya selalu menambahkan angka 1 hingga 100 juta yang dapat dilakukan pada komputer saya dalam waktu kurang dari satu menit untuk beberapa solusi.

Inilah hasilnya:

Python

:; seq 100000000 | python -c 'import sys; print sum(map(int, sys.stdin))'
5000000050000000
# 30s
:; seq 100000000 | python -c 'import sys; print sum(int(s) for s in sys.stdin)'
5000000050000000
# 38s
:; seq 100000000 | python3 -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 27s
:; seq 100000000 | python3 -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 22s
:; seq 100000000 | pypy -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 11s
:; seq 100000000 | pypy -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 11s

Awk

:; seq 100000000 | awk '{s+=$1} END {print s}'
5000000050000000
# 22s

Tempel & Bc

Ini kehabisan memori pada mesin saya. Ini berfungsi untuk setengah ukuran input (angka 50 juta):

:; seq 50000000 | paste -s -d+ - | bc
1250000025000000
# 17s
:; seq 50000001 100000000 | paste -s -d+ - | bc
3750000025000000
# 18s

Jadi saya kira itu akan mengambil ~ 35 untuk 100 juta angka.

Perl

:; seq 100000000 | perl -lne '$x += $_; END { print $x; }'
5000000050000000
# 15s
:; seq 100000000 | perl -e 'map {$x += $_} <> and print $x'
5000000050000000
# 48s

Rubi

:; seq 100000000 | ruby -e "puts ARGF.map(&:to_i).inject(&:+)"
5000000050000000
# 30s

C

Hanya untuk perbandingan, saya menyusun versi C dan menguji ini juga, hanya untuk mengetahui seberapa jauh lebih lambat solusi berbasis alat.

#include <stdio.h>
int main(int argc, char** argv) {
    long sum = 0;
    long i = 0;
    while(scanf("%ld", &i) == 1) {
        sum = sum + i;
    }
    printf("%ld\n", sum);
    return 0;
}

 

:; seq 100000000 | ./a.out 
5000000050000000
# 8s

Kesimpulan

C tentu saja tercepat dengan 8s, tetapi solusi Pypy hanya menambahkan sedikit overhead sekitar 30% menjadi 11s . Tapi, agar adil, Pypy tidak sepenuhnya standar. Kebanyakan orang hanya menginstal CPython yang jauh lebih lambat (22-an), persis secepat solusi populer Awk.

Solusi tercepat berdasarkan pada alat standar adalah Perl (15s).

Alfe
sumber
2
The paste+ bcPendekatan itu hanya apa yang saya cari untuk jumlah nilai hex, terima kasih!
Tomislav Nakic-Alfirevic
1
Hanya untuk bersenang-senang, di Rust:use std::io::{self, BufRead}; fn main() { let stdin = io::stdin(); let mut sum: i64 = 0; for line in stdin.lock().lines() { sum += line.unwrap().parse::<i64>().unwrap(); } println!("{}", sum); }
Jocelyn
jawaban yang luar biasa. bukan untuk mengalah tetapi itu adalah kasus bahwa jika Anda memutuskan untuk memasukkan hasil yang berjalan lebih lama, jawabannya akan lebih dahsyat!
Steven Lu
@ SevenLu Saya merasa jawabannya hanya akan lebih lama dan dengan demikian kurang mengagumkan (untuk menggunakan kata-kata Anda). Tapi saya bisa mengerti bahwa perasaan ini tidak perlu dibagikan oleh semua orang :)
Alfe
Berikutnya: numba + parallelisation
gerrit
17

Bash polos satu liner

$ cat > /tmp/test
1 
2 
3 
4 
5
^D

$ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))
Khaja Minhajuddin
sumber
7
Tidak perlu kucing : echo $(( $( tr "\n" "+" < /tmp/test) 0 ))
agc
2
trbukan "Bash biasa" / nitpick
Benjamin W.
17

Solusi BASH, jika Anda ingin menjadikan ini sebagai perintah (mis. Jika Anda harus sering melakukan ini):

addnums () {
  local total=0
  while read val; do
    (( total += val ))
  done
  echo $total
}

Kemudian penggunaan:

addnums < /tmp/nums
Jay
sumber
14

Saya pikir AWK adalah apa yang Anda cari:

awk '{sum+=$1}END{print sum}'

Anda dapat menggunakan perintah ini baik dengan meneruskan daftar angka melalui input standar atau dengan mengirimkan file yang berisi angka sebagai parameter.

Paolo
sumber
11

Berikut ini berfungsi di bash:

I=0

for N in `cat numbers.txt`
do
    I=`expr $I + $N`
done

echo $I
Francisco Canedo
sumber
1
Ekspansi perintah harus digunakan dengan hati-hati ketika file dapat berukuran besar secara sewenang-wenang. Dengan numbers.txt sebesar 10MB, cat numbers.txtlangkah itu akan bermasalah.
Giacomo
1
Memang, bagaimanapun (jika bukan untuk solusi yang lebih baik ditemukan di sini) saya akan menggunakan ini sampai saya benar-benar mengalami masalah itu.
Francisco Canedo
11

Anda dapat menggunakan num-utils, meskipun mungkin terlalu banyak untuk apa yang Anda butuhkan. Ini adalah sekumpulan program untuk memanipulasi angka dalam shell, dan dapat melakukan beberapa hal bagus, termasuk tentu saja, menambahkannya. Agak ketinggalan zaman, tetapi masih berfungsi dan dapat berguna jika Anda perlu melakukan sesuatu yang lebih.

http://suso.suso.org/programs/num-utils/

sykora
sumber
Contoh: numsum numbers.txt.
agc
9

Saya menyadari ini adalah pertanyaan lama, tetapi saya cukup menyukai solusi ini untuk membagikannya.

% cat > numbers.txt
1 
2 
3 
4 
5
^D
% cat numbers.txt | perl -lpe '$c+=$_}{$_=$c'
15

Jika ada minat, saya akan menjelaskan cara kerjanya.

Nym
sumber
10
Tolong jangan. Kami ingin berpura-pura bahwa n dan p adalah hal-hal semantik bagus, bukan hanya beberapa pintar tali paste;)
Hobbs
2
Ya tolong, jelaskan :) (Saya bukan tipe pria Perl.)
Jens
1
Coba jalankan "perl -MO = Deparse -lpe '$ c + = $ _} {$ _ = $ c'" dan melihat output, pada dasarnya -l menggunakan baris baru dan pemisah input dan output, dan -p mencetak setiap baris. Tetapi untuk melakukan '-p', perl pertama-tama menambahkan beberapa plat boiler (yang -MO = Deparse) akan menunjukkan kepada Anda, tetapi kemudian hanya mengganti dan mengkompilasi. Anda dapat menyebabkan blok tambahan dimasukkan dengan bagian '} {' dan mengelabunya agar tidak mencetak pada setiap baris, tetapi mencetak di bagian paling akhir.
Nym
9

Bash murni dan dalam satu baris :-)

$ cat numbers.txt
1
2
3
4
5
6
7
8
9
10


$ I=0; for N in $(cat numbers.txt); do I=$(($I + $N)); done; echo $I
55
Oliver Ertl
sumber
Mengapa ada dua ((tanda kurung ))?
Atcold
Bash tidak benar-benar murni karena kucing. buat bash murni dengan mengganti kucing dengan$(< numbers.txt)
Dani_l
9
sed 's/^/.+/' infile | bc | tail -1
Dominique
sumber
6

Alternatif Perl murni, cukup mudah dibaca, tidak ada paket atau opsi yang diperlukan:

perl -e "map {$x += $_} <> and print $x" < infile.txt
Clint
sumber
atau sedikit lebih pendek: perl -e 'map {$ x + = $ _} <>; print $ x 'infile.txt
Avi Tevet
Memori yang dibutuhkan hampir 2GB untuk input besar 10 juta angka
Amit Naidu
6

Untuk Pecinta Ruby

ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt
johnlinvc
sumber
5

Tidak dapat menghindari mengirimkan ini:

jot 1000000 | sed '2,$s/$/+/;$s/$/p/' | dc

Ditemukan di sini:
Kebanyakan unix shell satu-liner yang elegan untuk menjumlahkan daftar jumlah presisi yang sewenang-wenang?

Dan berikut ini adalah kelebihan khusus dari awk, bc dan teman-teman:

  • itu tidak tergantung pada buffering dan karenanya tidak tersumbat dengan input yang sangat besar
  • itu menyiratkan tidak ada presisi tertentu - atau ukuran bilangan bulat untuk hal itu - batas
  • tidak perlu kode yang berbeda, jika nomor floating point perlu ditambahkan
fgeorgatos
sumber
Harap sertakan kode yang terkait dengan pertanyaan dalam jawaban dan tidak merujuk ke tautan
Ibo
5

Menggunakan utilisasi GNU datamash :

seq 10 | datamash sum 1

Keluaran:

55

Jika input data tidak teratur, dengan spasi dan tab di tempat ganjil, ini dapat membingungkan datamash, maka gunakan -Wsakelar:

<commands...> | datamash -W sum 1

... atau gunakan truntuk membersihkan spasi:

<commands...> | tr -d '[[:blank:]]' | datamash sum 1
agc
sumber
4

Versi saya:

seq -5 10 | xargs printf "- - %s" | xargs  | bc
Vytenis Bivainis
sumber
2
Lebih pendek:seq -s+ -5 10 | bc
agc
3

Anda bisa melakukannya dengan python, jika Anda merasa nyaman:

Tidak diuji, cukup diketik:

out = open("filename").read();
lines = out.split('\n')
ints = map(int, lines)
s = sum(ints)
print s

Sebastian menunjukkan naskah satu liner:

cat filename | python -c"from fileinput import input; print sum(map(int, input()))"
Tiago
sumber
python -c "dari input impor fileinput; jumlah cetak (peta (int, input ()))" numbers.txt
jfs
2
kucing terlalu sering digunakan, mengarahkan stdin dari file: python -c "..." <numbers.txt
Giacomo
2
@rjack: catdigunakan untuk menunjukkan bahwa skrip berfungsi baik untuk stdin dan untuk file dalam argv [] (seperti while(<>)di Perl). Jika input Anda ada dalam file maka '<' tidak perlu.
jfs
2
Tetapi < numbers.txtmenunjukkan bahwa ia bekerja pada stdin sama baiknya cat numbers.txt |. Dan itu tidak mengajarkan kebiasaan buruk.
Xiong Chiamiov
3
$ cat n
2
4
2
7
8
9
$ perl -MList::Util -le 'print List::Util::sum(<>)' < n
32

Atau, Anda bisa mengetikkan angka di baris perintah:

$ perl -MList::Util -le 'print List::Util::sum(<>)'
1
3
5
^D
9

Namun, yang satu ini menyeruput file tersebut sehingga itu bukan ide yang baik untuk digunakan pada file besar. Lihat j_random_hacker jawaban yang menghindari menghirup.

Sinan Ünür
sumber
3

Berikut ini harus berfungsi (dengan asumsi nomor Anda adalah bidang kedua pada setiap baris).

awk 'BEGIN {sum=0} \
 {sum=sum + $2} \
END {print "tot:", sum}' Yourinputfile.txt
James Anderson
sumber
2
Anda tidak benar-benar membutuhkan bagian {sum = 0}
Uphill_ What '1
3

One-liner di Racket:

racket -e '(define (g) (define i (read)) (if (eof-object? i) empty (cons i (g)))) (foldr + 0 (g))' < numlist.txt
b2coutts
sumber
3

C (tidak disederhanakan)

seq 1 10 | tcc -run <(cat << EOF
#include <stdio.h>
int main(int argc, char** argv) {
    int sum = 0;
    int i = 0;
    while(scanf("%d", &i) == 1) {
        sum = sum + i;
    }
    printf("%d\n", sum);
    return 0;
}
EOF)
Greg Bowyer
sumber
Saya harus mengubah komentar. Tidak ada yang salah dengan jawabannya - ini cukup bagus. Namun, untuk menunjukkan bahwa komentar itu membuat jawabannya luar biasa, saya hanya mengangkat komentar itu.
bballdave025
3

Permintaan maaf sebelumnya untuk keterbacaan backticks ("` "), tetapi ini bekerja dalam cangkang selain bash dan karenanya lebih mudah ditempel. Jika Anda menggunakan shell yang menerimanya, format $ (command ...) jauh lebih mudah dibaca (dan dengan demikian dapat ditiadakan) daripada `command ...` jadi jangan ragu untuk memodifikasi kewarasan Anda.

Saya memiliki fungsi sederhana di bashrc saya yang akan menggunakan awk untuk menghitung sejumlah item matematika sederhana

calc(){
  awk 'BEGIN{print '"$@"' }'
}

Ini akan melakukan +, -, *, /, ^,%, sqrt, sin, cos, kurung .... (dan lebih banyak tergantung pada versi awk Anda) ... Anda bahkan dapat menikmati printf dan memformat floating point output, tapi ini semua biasanya saya butuhkan

untuk pertanyaan khusus ini, saya cukup melakukan ini untuk setiap baris:

calc `echo "$@"|tr " " "+"`

jadi blok kode untuk menjumlahkan setiap baris akan terlihat seperti ini:

while read LINE || [ "$LINE" ]; do
  calc `echo "$LINE"|tr " " "+"` #you may want to filter out some lines with a case statement here
done

Itu jika Anda hanya ingin menjumlahkannya baris demi baris. Namun untuk total setiap angka dalam datafile

VARS=`<datafile`
calc `echo ${VARS// /+}`

btw jika saya perlu melakukan sesuatu dengan cepat di desktop, saya menggunakan ini:

xcalc() { 
  A=`calc "$@"`
  A=`Xdialog --stdout --inputbox "Simple calculator" 0 0 $A`
  [ $A ] && xcalc $A
}
technosaurus
sumber
2
Jenis shell kuno apa yang Anda gunakan yang tidak mendukung $()?
nyuszika7h