Sumowanie wartości bez pętelek

Posted on Sat 06 November 2004 in Tips text {sed, awk, perl, etc.} • [2 min read]

Mam polecenie, ktore zwraca takie wartosci:

111
123
124
125

Mysle sobie, zeby to cholerstwo przepuscic przez xargs expr +, zeby mi te wartosci zsumowalo. Petelek wolalbym unikac. Da sie?

Bez petelek? W jaki sposob? Nawet gdyby ta petelka miala skonstruowac wyrazenie, powiedzmy, LISP-u i przekazac do ewaluacji. Chyba, ze to sa zawsze cztery i zawsze te same liczby. No to wtedy "echo 483" jest tym co potrzeba. :-)

Mozna ta petelke "schowac"

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

Podejrzewam, ze sztuki takie jak

echo 111 123 124 125 +++p |dc

nie sa satysfakcjonujace. :-) Chociaz

( echo 111; echo 123; echo 124; echo 125; echo +++p ) |dc

da taki sam wynik.


data=$( seq 122 125 )
sum=$(expr $(echo $data | sed 's/ / + /g'))
echo $sum

Tyle, ze petelka jest tez tutaj "schowana" w 'sed ..../g'. 'seq' po to zeby zasymulowac ten proces ktory daje kolumienke liczb. Ale, ale. Rzeczywiscie mozna zrobic ta petle przy pomocy xargs.

data=$(seq 122 125 | xargs -i'x' echo -n "x + " ; echo 0)
expr $data

Bardzo to krucha ta konstrukcja. Co zlego z jawnymi petlami?


Nie warto unikać pętli.

seq 122 125 | perl -e 'while (<>) {$sum += $_} print "$sum\\n"'

No, jak jawne petle sa ok, i sa to liczby calkowite, to perl tez nie jest potrzebne.

$ seq 3000 |(while read r; do s=$((r+s)); done; echo $s)
4501500

Napewno bedzie szybciej niz 'xargs' i 'expr'. :-) Z tym, ze przy odpowiednio duzych sumach moze sie zrobic "overflow" podczas gdy perl czy awk i ten szczegol ukryja. perl czy awk bedzie znaczenie szybsze niz powyzsze - jezeli tych liczb jest dostatecznie duzo zeby sie to dalo mierzyc.

$ time seq 3000 6000 |(while read r; do s=$((r+s)); done; echo $s)
13504500
real 0m0.272s
user 0m0.250s
sys 0m0.010s