Her satıra bir tane olmak üzere tamsayıları toplamak için Shell komutu?


867

Ben (giriş olarak) metin, her satır tek bir tamsayı içeren ve bu tamsayıların toplamı çıkış kabul edecek bir komut arıyorum.

Biraz arka plan olarak, zamanlama ölçümleri içeren bir günlük dosyası var. İlgili satırlar için selamlama ve biraz sedyeniden biçimlendirme yoluyla bu dosyadaki tüm zamanlamaları listeleyebilirim. Toplamı bulmak istiyorum. Nihai toplamı yapmak için bu ara çıkışı herhangi bir komuta bağlayabilirim. Her zaman exprgeçmişte kullandım , ancak RPN modunda çalışmadığı sürece bununla başa çıkacağını düşünmüyorum (ve o zaman bile zor olurdu).

Tamsayıların toplamını nasıl alabilirim?


2
Bu bir süre önce sorduğum bir soruya çok benziyor: stackoverflow.com/questions/295781/…
An̲̳̳drew

5
Bu soruyu gerçekten çok sayıda doğru (veya en azından çalışan) cevap olduğu için seviyorum.
Francisco Canedo

Bu soru kod golf için bir sorun gibi geliyor. codegolf.stackexchange.com :)
Gordon Bean

Yanıtlar:


1322

Biraz awk yapmalı mı?

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

Not: 2 ^ 31 (2147483647) değerini aşan bir şey ekleyecekseniz awk'nin bazı sürümlerinde bazı garip davranışlar vardır. Daha fazla arka plan için yorumlara bakın. Bir öneri aşağıdakilerden printfziyade kullanmaktır print:

awk '{s+=$1} END {printf "%.0f", s}' mydatafile

7
Bu odada çok fazla garip aşk var! Böyle basit bir komut dosyasının sadece 1 $ 'ı 2 $' a değiştirerek ikinci bir veri sütununu eklemek için nasıl değiştirilebileceğini seviyorum
Paul Dixon

2
Girişi bir akış olarak işleyeceği için pratik bir sınır yoktur. Bu nedenle, X satırlarından oluşan bir dosyayı işleyebiliyorsa, X + 1'i işleyebileceğinden emin olabilirsiniz.
Paul Dixon

4
Bir keresinde tatil aracı aracılığıyla çalıştırılan bir awk komut dosyası ile ilkel bir posta listesi işlemcisi yazdım. İyi zamanlar. :)
LS

2
sadece bunu bir için kullandım: tüm belgelerin sayfalarını sayın script:ls $@ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk '{s+=$2} END {print s}'
uçan koyun

8
Dikkat edin, 2147483647'den (yani, 2 ^ 31) daha büyük sayılarla çalışmayacaktır, çünkü awk 32 bit imzalı bir tamsayı gösterimi kullanır. awk '{s+=$1} END {printf "%.0f", s}' mydatafileBunun yerine kullanın .
Giancarlo Sportelli

665

Yapıştır genellikle birden çok dosyanın satırlarını birleştirir, ancak bir dosyanın tek tek satırlarını tek bir satıra dönüştürmek için de kullanılabilir. Sınırlayıcı bayrağı, bc'ye x + x tipi bir denklem geçirmenize izin verir.

paste -s -d+ infile | bc

Alternatif olarak, stdin'den borulama yaparken,

<commands> | paste -s -d+ - | bc

1
Çok hoş! Ben sadece daha iyi ayrıştırmak için, "+" önce bir boşluk koymak olurdu, ama bu macun ve sonra bc bazı bellek numaraları boru için çok kullanışlı oldu.
Michael H.

73
Awk çözümüne göre hatırlaması ve yazması çok daha kolaydır. Ayrıca, dosya adı olarak pastebir tire işareti kullanabileceğinizi unutmayın -- bu, önce bir dosya oluşturmaya gerek kalmadan bir komutun çıkışından gelen sayıları macunun standart çıktısına <commands> | paste -sd+ - | bc
George

19
100 milyon rakamlı bir dosyam var. Awk komutu 21s alır; Yapıştır komutu 41 saniye sürer. Ama yine de 'yapıştırmak' tanışmak güzel!
Abhi

4
@Abhi: İlginç: DI, awk komutunu bulmak için 20'leri alacaktı, bu yüzden 100 milyonu ve bir sayıyı deneyene kadar düzeldi: D
Mark K Cowan

6
@George Yine de dışarıda bırakabilirsiniz -. (Bir dosyayı stdin ile birleştirmek istiyorsanız kullanışlıdır ).
Alois Mahdal

128

Python'daki tek katmanlı sürüm:

$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"

Yukarıdaki bir astar sys.argv [] içindeki dosyalar için çalışmaz, ancak biri stackoverflow.com/questions/450799/…
jfs

Doğru- yazar o komut başka bir komuttan çıkış boru olacak gittiğini söyledi ve ben mümkün olduğunca kısa yapmaya çalışıyordu :)
dF.

39
Daha kısa versiyon olurdupython -c"import sys; print(sum(map(int, sys.stdin)))"
jfs

4
Bu cevabı okuma kolaylığı ve esnekliği için seviyorum. Ben bir dizin koleksiyonunda 10Mb daha küçük dosyaların ortalama boyutunu gerekli ve bunu değiştirdi: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 23:12

1
Ayrıca bazı metinler karışık ise sayı olmayanları da filtreleyebilirsiniz:import sys; print(sum(int(''.join(c for c in l if c.isdigit())) for l in sys.stdin))
Granitosaurus

91

Yaygın olarak onaylanan çözüme büyük bir UYARI koyarım:

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

çünkü bu formda awk 32 bit işaretli bir tamsayı gösterimi kullanır: 2147483647'yi (yani, 2 ^ 31) aşan toplamlar için taşacaktır.

Daha genel bir cevap (tamsayıları toplamak için):

awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD

Printf () neden burada yardımcı oluyor? Toplama kodu aynı olduğu için int'in taşması bundan önce olmuş olacaktır.
Robert Klemme

9
Çünkü problem aslında "print" fonksiyonunda. Awk 64 bit tamsayılar kullanır, ancak bazı nedenlerden dolayı baskı 32 bite ölçeklendirir.
Giancarlo Sportelli

4
Yanılmıyorsam, yazdırma hatası en azından awk 4.0.1 & bash 4.3.11 için düzeltilmiş gibi görünüyor: echo -e "2147483647 \n 100" |awk '{s+=$1}END{print s}'gösterir2147483747
Xen2050

4
Şamandıralar kullanıldığında yeni bir sorun ortaya çıkıyor: echo 999999999999999999 | awk '{s+=$1} END {printf "%.0f\n", s}'Üretiyor1000000000000000000
Patrick

1
64bit sistemlerde sadece "% ld" kullanıldığında printf'in 32bit'e kadar kesilmemesi gerekir mi? @Patrick'in işaret ettiği gibi, şamandıralar burada harika bir fikir değil.
yerforkferchips


66
dc -f infile -e '[+z1<r]srz1<rp'

Eksi işaretiyle önek eklenmiş negatif sayıların dc, _önek yerine -önek kullandığından, çevrilmesi gerektiğini unutmayın . Örneğin, üzerinden tr '-' '_' | dc -f- -e '...'.

Edit: Bu cevap "müstehcenlik için" çok oy aldığından, İşte ayrıntılı bir açıklama:

İfade [+z1<r]srz1<rp aşağıdakileri yapar :

[   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

Sahte kod olarak:

  1. "Add_top_of_stack" öğesini şu şekilde tanımlayın:
    1. Yığındaki en yüksek iki değeri kaldırın ve sonucu geri ekleyin
    2. Yığının iki veya daha fazla değeri varsa, "add_top_of_stack" komutunu tekrar tekrar çalıştırın
  2. Yığının iki veya daha fazla değeri varsa, "add_top_of_stack" komutunu çalıştırın
  3. Sonucu yazdırın, şimdi yığınta kalan tek öğe

Basitliğini ve gücünü gerçekten anlamak için , yukarıdaki dckomutların bazılarını uygulayan dcve yukarıdaki komutun Python sürümünü çalıştıran çalışan bir Python betiği :

### 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()

2
dc sadece kullanmak için tercih edilen araçtır. Ama bunu biraz daha az yığın ops ile yaparım. Bütün hatların gerçekten bir numara içermesi Varsayalım ki: (echo "0"; sed 's/$/ +/' inp; echo 'pq')|dc.
ikrabbe

5
Online algoritması: dc -e '0 0 [+?z1<m]dsmxp'. Bu nedenle, işlemeden önce tüm sayıları yığına kaydetmiyoruz, ancak bunları tek tek okuyup işliyoruz (bir satır birden fazla sayı içerebileceğinden, daha kesin olmak gerekirse, satır satır). Boş satırın bir giriş sırasını sonlandırabileceğini unutmayın.
ruvim

@ikrabbe bu harika. Aslında bir karakter daha kısaltılabilir: ikamedeki boşluk sedkaldırılabilir, çünkü dc argümanlar ve operatörler arasındaki boşluklar umursamaz. (echo "0"; sed 's/$/+/' inputFile; echo 'pq')|dc
WhiteHotLoveTiger

58

İle JQ :

seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'

7
Bunu sevdim çünkü sanırım gerçekten hatırlayabileceğim kadar açık ve kısa.
Alfe

46

Saf ve kısa bash.

f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))

9
Bu en iyi çözümdür, çünkü ilk satırı değiştirirseniz herhangi bir alt işlem oluşturmaz f=$(<numbers.txt).
loentar

1
stdin girdisine sahip olmanın herhangi bir yolu var mı? borudan mı?
njzk2

@ njzk2 f=$(cat); echo $(( ${f//$'\n'/+} ))Bir komut dosyası koyarsanız , o komut dosyasına herhangi bir şey ekleyebilir veya etkileşimli stdin girdisi için bağımsız değişkenler olmadan onu başlatabilirsiniz (Control-D ile sonlandırın).
mklement0

5
@loentar Bu <numbers.txtbir gelişmedir, ancak genel olarak bu çözüm yalnızca küçük girdi dosyaları için etkilidir; Örneğin, 1.000 giriş satırlı bir dosya ile kabul edilen awkçözüm makinemde yaklaşık 20 kat daha hızlıdır ve daha az bellek tüketir, çünkü dosya bir kerede okunmaz.
mklement0

2
Buna ulaştığımda neredeyse umudumu yitirmiştim. Saf bok!
Ömer Akhter

37
perl -lne '$x += $_; END { print $x; }' < infile.txt

4
Ve onları geri ekledim: "-l", çıktının kabuk `` backticks ve çoğu programın beklediği gibi LF sonlandırılmasını sağlar ve "<", bu komutun bir boru hattında kullanılabileceğini gösterir.
j_random_hacker

Haklısın. Bir mazeret olarak: Perl tek satırlarındaki her karakter benim için zihinsel bir çalışma gerektirir, bu yüzden mümkün olduğunca çok karakter dizmeyi tercih ederim. Bu durumda alışkanlık zararlıdır.
jfs

2
Her şeyi RAM'e yüklemeyen birkaç çözümden biri.
Erik Aronesty

28

On beş sentim:

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

Misal:

$ 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

Benim girişi boş satırlar içerebilir, bu yüzden burada artı ne yayınlanmıştır kullanılan grep -v '^$'. Teşekkürler!
James Oravec

vay!! cevabınız inanılmaz! benim adım tüm kişisel favori
thahgr

Bunu seviyorum ve boru hattı için +1. Benim için çok basit ve kolay bir çözüm
Gelin Luo

24

Mevcut cevaplar hakkında kısa bir değerlendirme yaptım.

  • sadece standart araçlar kullanın ( luaveya gibi şeyler için özür dilerim rocket),
  • gerçek tek gömlekli,
  • çok sayıda (100 milyon) rakam ekleyebilir ve
  • hızlı (bir dakikadan uzun sürenleri görmezden geldim).

Her zaman birkaç ila birkaç dakika içinde makinemde yapılabilen 1 ila 100 milyon arasındaki sayıları ekledim.

Sonuçlar burada:

piton

:; 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

Yapıştır & Bc

Bu makinemde bellek kalmadı. Girdinin yarısı kadar çalıştı (50 milyon sayı):

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

Bu yüzden sanırım 100 milyon sayı için ~ 35s alacaktı.

Perl

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

Yakut

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

C

Sadece karşılaştırma için, C sürümünü derledim ve bunu da test ettim, sadece araç tabanlı çözümlerin ne kadar yavaş olduğu hakkında bir fikrim var.

#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

Sonuç

C elbette 8 saniye ile en hızlı, ancak Pypy çözümü sadece yaklaşık% 30 ila 11 saniye arasında çok az ek yük getiriyor . Ancak, adil olmak gerekirse, Pypy tam olarak standart değildir. Çoğu insan sadece CPython yüklüdür ve bu da popüler Awk çözümü kadar hızlıdır.

Standart araçlara dayalı en hızlı çözüm Perl'dir (15s).


2
paste+ bcYaklaşımı sadece ben toplamına onaltılık değerler için teşekkür arıyordu ne!
Tomislav Nakic-Alfirevic

1
Rust için sadece eğlence için: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

harika bir cevap. nitpick değil ama bu daha uzun süren sonuçları dahil etmeye karar verirseniz, cevabın daha da harika
Steven Lu

@StevenLu Cevabın daha uzun ve dolayısıyla daha az harika olacağını hissettim (kelimelerinizi kullanmak için). Ama bu hissin herkes tarafından paylaşılması gerekmediğini anlayabiliyorum :)
Alfe

Sonraki: numba + paralelleştirme
gerrit

17

Düz bash bir astar

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

$ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))

7
Hiçbir kedi gerekli: echo $(( $( tr "\n" "+" < /tmp/test) 0 ))
agc

2
trtam olarak "düz Bash" / nitpick
Benjamin W.

17

BASH çözümü, bunu bir komut yapmak istiyorsanız (örneğin, bunu sık sık yapmanız gerekiyorsa):

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

Sonra kullanım:

addnums < /tmp/nums

14

AWK aradığın şey olduğunu düşünüyorum:

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

Bu komutu, numaralar listesini standart girdiden geçirerek veya sayıları içeren dosyayı parametre olarak geçirerek kullanabilirsiniz.



11

Aşağıdaki bash çalışır:

I=0

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

echo $I

1
Komut genişletme, dosyalar keyfi olarak büyük olduğunda dikkatli kullanılmalıdır. 10MB olan numbers.txt ile cat numbers.txtadım sorunlu olur.
Giacomo

1
Gerçekten de, (burada bulunan daha iyi çözümler için değilse) bu sorunla karşılaşana kadar bunu kullanacağım.
Francisco Canedo

11

Num-utils kullanabilirsiniz, ancak ihtiyacınız olan şey için aşırı olabilir. Bu, kabuktaki sayıları işlemek için bir dizi programdır ve elbette onları toplamak da dahil olmak üzere birkaç şık şey yapabilir. Biraz güncel değil, ama yine de çalışıyorlar ve daha fazla bir şey yapmanız gerekiyorsa yararlı olabilirler.

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


Örnek: numsum numbers.txt.
agc

9

Bunun eski bir soru olduğunun farkındayım, ancak bu çözümü paylaşacak kadar seviyorum.

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

İlgi varsa, nasıl çalıştığını açıklayacağım.


10
Lütfen yapma. -N ve -p'nin sadece bazı akıllı dize yapıştırmaları değil, güzel anlamsal şeyler olduğunu iddia etmek isteriz;)
ocaklar

2
Evet, açıkla :) (Ben bir Perl tipi adam değilim.)
Jens

1
"Perl -MO = Deparse -lpe '$ c + = $ _} {$ _ = $ c'" komutunu çalıştırmayı ve çıktıya bakmayı deneyin, temel olarak -l yeni satırları ve hem giriş hem de çıkış ayırıcılarını kullanır ve -p her satırı yazdırır. Ancak '-p' yapmak için, perl önce bazı kazan plakası ekler (ki -MO = Deparse) size gösterecektir, ancak daha sonra sadece ikame eder ve derler. Böylece, fazladan bir bloğun '} {' parçasıyla yerleştirilmesine neden olabilir ve her satıra yazdırmamak için kandırıp en sonunda yazdırabilirsiniz.
Nym

9

Saf bash ve tek astarlı :-)

$ 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

Neden iki ((parantez var ))?
Atcold

Kedi yüzünden gerçekten saf bir bash değil. kedi yerine onu saf bash yapmak$(< numbers.txt)
Dani_l


6

Alternatif saf Perl, oldukça okunabilir, paket veya seçenek gerekmez:

perl -e "map {$x += $_} <> and print $x" < infile.txt

veya biraz daha kısa: perl -e 'haritası {$ x + = $ _} <>; print x 'infile.txt
Avi Tevet

10 milyonluk büyük bir giriş için gereken bellek yaklaşık 2
GB'dir

6

Ruby Lovers için

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

5

Bunu göndermekten kaçınamazsınız:

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

Burada bulunur:
En hassas unix kabuk keyfi bir dizi sayı listesini toplamak için?

Ve işte awk, bc ve arkadaşlara göre özel avantajları:

  • tamponlamaya bağlı değildir ve bu nedenle gerçekten büyük girdilerle boğulmaz
  • belirli bir hassasiyet veya bu konu için tamsayı boyutu anlamına gelmez
  • kayan nokta numaralarının eklenmesi gerekiyorsa, farklı koda gerek yoktur

Lütfen soruyla ilgili kodu cevaba ekleyin ve bir bağlantıya başvurmayın
Ibo

5

Kullanılması GNU datamash util :

seq 10 | datamash sum 1

Çıktı:

55

Giriş verileri düzensizse, garip yerlerde boşluklar ve sekmeler varsa, bu kafa karıştırıcı olabilir datamash, daha sonra -Wanahtarı kullanın :

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

... veya trboşlukları temizlemek için kullanın :

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


3

Eğer rahat hissediyorsanız python ile yapabilirsiniz:

Test edilmedi, sadece yazdı:

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

Sebastian tek satırlık bir senaryoya dikkat çekti:

cat filename | python -c"from fileinput import input; print sum(map(int, input()))"

python -c "dosya girişi içe aktarma girişinden; toplamı yazdır (harita (int, girdi ()))" numbers.txt
jfs

2
kedi aşırı, stdin dosyasını dosyaya yönlendir: python -c "..." <numbers.txt
Giacomo

2
@rjack: catbetiğin hem stdin hem de argv [] ( while(<>)Perl'deki gibi ) dosyaları için çalıştığını göstermek için kullanılır . Girişiniz bir dosyadaysa '<' gereksizdir.
jfs

2
Ama < numbers.txtaynı stdin üzerinde de çalıştığını gösteriyor cat numbers.txt |. Ve kötü alışkanlıkları öğretmez.
Xiong Chiamiov

3
$ kedi n
2
4
2
7
8
9
$ perl -MList::Util -le 'print List::Util::sum(<>)' < n
32

Veya komut satırındaki sayıları yazabilirsiniz:

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

Ancak, bu dosyada büyük dosyalar üzerinde kullanmak iyi bir fikir değil, bu yüzden slurps. Kaymayı önleyen j_random_hacker'ın cevabına bakınız .


3

Aşağıdakiler işe yaramalıdır (numaranızın her satırdaki ikinci alan olduğu varsayılarak).

awk 'BEGIN {sum=0} \
 {sum=sum + $2} \
END {print "tot:", sum}' Yourinputfile.txt

2
Gerçekten {sum = 0} bölümüne ihtiyacınız yok
Uphill_ Ne '1

3

Rakette Tek Astar:

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

3

C (basitleştirilmemiş)

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)

Yorumu iptal etmek zorunda kaldım. Cevapta yanlış bir şey yok - oldukça iyi. Ancak, yorumun cevabı harika yaptığını göstermek için, sadece yorumu destekliyorum.
bballdave025

3

İğnelerin okunabilirliği için şimdiden özür dileriz ("` "), ancak bunlar bash dışındaki kabuklarda çalışır ve bu nedenle daha uzatılabilir. Kabul eden bir kabuk kullanırsanız, $ (command ...) formatı `command ... '' dan çok daha okunabilir (ve dolayısıyla hata ayıklanabilir) olur, bu nedenle akıl sağlığınız için değişiklik yapmaktan çekinmeyin.

Benim bashrc basit bir matematik öğeleri hesaplamak için awk kullanacak basit bir işlevi var

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

Bu +, -, *, /, ^,%, sqrt, sin, cos, parantez .... (ve daha fazlası awk sürümünüze bağlı olarak) yapacaktır ... printf ve format kayan nokta ile bile süsleyebilirsiniz çıktı, ama normalde tüm ihtiyacım olan bu

bu özel soru için, her satır için bunu yapardım:

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

böylece her satırı toplamak için kod bloğu şöyle görünecektir:

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

Onları sadece satır satır toplamak istiyorsanız. Ancak veri dosyasındaki her sayının toplamı için

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

btw masaüstünde hızlı bir şey yapmak gerekirse, ben bunu kullanın:

xcalc() { 
  A=`calc "$@"`
  A=`Xdialog --stdout --inputbox "Simple calculator" 0 0 $A`
  [ $A ] && xcalc $A
}

2
Ne tür bir antik kabuk kullanıyorsunuz desteklemiyor $()?
nyuszika7h
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.