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"
... | awk '{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.
... | 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