Есть файл вида$cat total.bytes
1962647280
154580283
85368270
256233601
2448176455
3211021168
392011779
.........т.е просто числа на каждой строке
нужно просуммировать их все - чтоб на выходе было одно число.
Я не нашел какой-нибудь встроенной функции для подсчета такого массива, и написал скрипт:#!/bin/sh
cat total.bytes | \
while read line;
do
let y=y+line;
done
echo $y
скрипт выводит$./add.sh
1962647280
2117227563
-2092371463
-1836137862
311345785
-1836137864
-1444126085
-710494993
1436988654
-1190184973Т.е первые два числа сложил, а потом почему-то минусы какие-то появляются
что делаю не так?
>Есть файл вида
>
>$cat total.bytes
>1962647280
>154580283
>85368270
>256233601
>2448176455
>3211021168
>392011779в минус уходит из-за переполнения int.
попробуйте так:
sum = 0; cat total.bytes | while read num ; do sum=`echo $sum+$num" | bc -q` ; done ; echo $sum
а еще лучше так
result=`sum=0 ; (while read num; do sum=$(echo "$sum+$num" | bc -q); done ; echo $sum) < total.bytes`
echo $result
$ cat total.bytes
1962647280
154580283
85368270
2562336012448176455
3211021168
392011779
$ ( tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'; echo ) |bc
8510038836
$ tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'|xargs|bc
8510038836
$ egrep -o '[0-9]+' <total.bytes |tr "\n" "+" |sed 's!+$!\n!'|bc
8510038836
$ _
>[оверквотинг удален]
>392011779
>
>
>$ ( tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'; echo ) |bc
>8510038836
>$ tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'|xargs|bc
>8510038836
>$ egrep -o '[0-9]+' <total.bytes |tr "\n" "+" |sed 's!+$!\n!'|bc
>8510038836
>$ _То ли я что-то не то делаю, но у меня на все это syntax error выдает
>[оверквотинг удален]
>392011779
>
>
>$ ( tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'; echo ) |bc
>8510038836
>$ tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'|xargs|bc
>8510038836
>$ egrep -o '[0-9]+' <total.bytes |tr "\n" "+" |sed 's!+$!\n!'|bc
>8510038836
>$ _как бы bc не отвалился, хз сколько там чисел
echo `cat total.bytes` | tr " " "+" | bc
это все хорошо, а если там чисел столько что bc отвалится
>как бы bc не отвалился, хз сколько там чисел
>echo `cat total.bytes` | tr " " "+" | bc
>это все хорошо, а если там чисел столько что bc отвалитсяВо, самый короткий вариант, и работает в баше и в sh!!!
>[оверквотинг удален]
>>8510038836
>>$ tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'|xargs|bc
>>8510038836
>>$ egrep -o '[0-9]+' <total.bytes |tr "\n" "+" |sed 's!+$!\n!'|bc
>>8510038836
>>$ _
>
>как бы bc не отвалился, хз сколько там чисел
>echo `cat total.bytes` | tr " " "+" | bc
>это все хорошо, а если там чисел столько что bc отвалитсякакая настойчивая мысль....)))))))))
>>$ ( tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'; echo ) |bc
>>$ tr "\n" "+" <total.bytes |sed 's!+\+!+!g;s!^+\|+$!!g'|xargs|bc
>>$ egrep -o '[0-9]+' <total.bytes |tr "\n" "+" |sed 's!+$!\n!'|bc
>как бы bc не отвалился, хз сколько там чиселДействительно! %)
>echo `cat total.bytes` | tr " " "+" | bc
>это все хорошо, а если там чисел столько что bc отвалится$ cat ./x41
#!/bin/bashn=10
for((i=1;i<7;i++)); do
yes | head -$n |sed 's!y!1000000001!' | (\
/usr/bin/time bc <(echo 'sum=0;while((val=read())!=0){sum+=val}; sum') |\tr -d "\n"|wc -c
) 2>&1 |tr "\n" " "|awk '{print '"$((${#n}-1))"'" "$NF" "$1" "$3" "$4;exit}'
n="${n}0"
done
#
#done$ ./x41
1 11 0.00user 0:00.00elapsed 0%CPU
2 12 0.00user 0:00.00elapsed 44%CPU
3 13 0.01user 0:00.01elapsed 70%CPU
4 14 0.09user 0:00.10elapsed 85%CPU
5 15 0.88user 0:01.06elapsed 83%CPU
6 16 8.82user 0:10.20elapsed 86%CPU
$ _Вот такой вариант, соответственно, не подавился суммированием миллиона (десяти лениво было ждать) чисел:
bc <(echo 'sum=0;while((val=read())!=0){sum+=val}; sum')
Из трёх моих первых до таких "высот" не дожил ни один: xargs умер раньше всех, а при передаче сотни тысяч(или типа того) слагаемых в виде строки 1+1+1+,,, bc слишком активно кушал память (типа, всю свободную и начинал "свопиться" = тормозить себя и всю систему).
PS: <(echo '...') - башизм, чтоб сэкономить "лишний" файл.
PPS: Первая колонка "бенчмарка" - log($числа_слагаемых), вторая - "длинна" суммы.
>bc <(echo 'sum=0;while((val=read())!=0){sum+=val}; sum')Обновился с Debian 4.0 "Etch" на Debian 5.0 "Lenny" (bc 1.06-20 -> 1.06.94-3, bash 3.1dfsg-8 -> 3.2-4 и проч.) и это заклинание больше не работает. "=read())!=0" в нём костыль, конечно, по сравнению с "while read val; do" в bash-е: конец файла от числа 0 не отличает. А в Lenny и вообще не работает...
>[оверквотинг удален]
>>256233601
>>2448176455
>>3211021168
>>392011779
>
>в минус уходит из-за переполнения int.
>
>попробуйте так:
>sum = 0; cat total.bytes | while read num ; do sum=`echo
>$sum+$num" | bc -q` ; done ; echo $sumТоже подумал что от переполнения, но когда сложил вручную несколько первых чисел, но все нормально
Ваш скрипт к сожалению не работает, там вроде кавычки забыли, я поставил, все равно не пашет
>[оверквотинг удален]
>>
>>попробуйте так:
>>sum = 0; cat total.bytes | while read num ; do sum=`echo
>>$sum+$num" | bc -q` ; done ; echo $sum
>
>Тоже подумал что от переполнения, но когда сложил вручную несколько первых чисел,
>но все нормально
>
>Ваш скрипт к сожалению не работает, там вроде кавычки забыли, я поставил,
>все равно не пашетА вот второй скрипт пашет, спасибо!
>#!/bin/sh
>cat total.bytes | \
>while read line;
>do
>let y=y+line;
>done
>echo $yОбратите особое внимание на строку с "let", она у вас не может работать.
$ cat total.bytes
1962647280
154580283
85368270
256233601
2448176455
3211021168
392011779$ cat script.sh
#!/bin/sh
while read line;
do
let y=$y+$line;
done < total.bytes
echo $y$ ./script.sh
8510038836
>[оверквотинг удален]
>while read line;
>do
> let y=$y+$line;
>done < total.bytes
>echo $y
>
>$ ./script.sh
>8510038836
>
>
Так тоже минусы выводит у меня!
>[оверквотинг удален]
>> let y=$y+$line;
>>done < total.bytes
>>echo $y
>>
>>$ ./script.sh
>>8510038836
>>
>>
>
>Так тоже минусы выводит у меня!А вы cat | while делаете или while .. done < file ?
В первом случае может неявно вызываться субшелл и как следствие переменная y может быть не видна т.к ее область видимости - субшелл, отсюда глюки.Что за система? (uname -a && sh --version) ?
>А вы cat | while делаете или while .. done < file
>?
>В первом случае может неявно вызываться субшелл и как следствие переменная y
>может быть не видна т.к ее область видимости - субшелл, отсюда
>глюки.
>
>Что за система? (uname -a && sh --version) ?$ cat xyz.sh
#!/bin/sh
while read line;
do
let m=$m+$line;
done < total.bytes.back
echo $m$ ./xyz.sh
1962647280
2117227563
-2092371463
-1836137862
311345785
-1836137864
-1444126085
-1444126085$ uname -a
FreeBSD 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Fri Apr 11 20:30:15 MSD 2008$ sh --version
Illegal option --
О, а если bash поставить, то работает!Дело в sh значит$ cat xyz.sh
#!/usr/local/bin/bash
while read line;
do
let m=$m+$line;
done < total.bytes.back
echo $m
$ ./xyz.sh
8510038836
>О, а если bash поставить, то работает!Дело в sh значитоднако суровый sh в freebsd :))
result=`y=0; (while read line; do let y=$y+$line; done ; echo $y) < total.bytes`
echo $resultчто буит?
>>О, а если bash поставить, то работает!Дело в sh значит
>
>однако суровый sh в freebsd :))
>
>result=`y=0; (while read line; do let y=$y+$line; done ; echo $y) <
>total.bytes`
>echo $result
>
>что буит?$ ./xyz.sh
1962647280 2117227563 -2092371463 -1836137862 311345785 -1836137864 -1444126085 -710494993 1436988654 -1190184973 957298674 -1190184975 338450189 623557529 790395966 924888457 -1222595192 138906228 1676938475 1857929764 1857956963 -765632036 1316748116 -1132369225 1015114422 1520280995 1520280995Тож самое, минусы.А как узнать версию sh?и его вообще можно обновить, в портах нету его
>Тож самое, минусы.А как узнать версию sh?и его вообще можно обновить, в
>портах нету егоуже можно не парится, итак видно что суровый :)
а минусы это переполнение (ибо сурово), поэтому во втором варианте я и предложил bc :)
>>О, а если bash поставить, то работает!Дело в sh значит
>однако суровый sh в freebsd :))Номальный POSIX Shell.
PS: А да - во фряхе _внезапно!_ bash зовётся bash'ем а не sh :)
awk 'BEGIN {c=0} {c=c+$0} END {printf("%.0f\n", c)}' total.bytes
>awk 'BEGIN {c=0} {c=c+$0} END {printf("%.0f\n", c)}' total.bytesЕсли точности плавающих - хватает, то да, так быстрее:
$ cat ./x5
#!/bin/bashn=10
for((i=1;i<8;i++)); do
yes | head -$n |sed 's!y!18446744073799!' | (\
/usr/bin/time gawk 'BEGIN {c=0} {c=c+$0} END {printf("%.0f\n", c)}' |\
tr -d "\n"
#|wc -c) 2>&1 |tr "\n" " "|awk '{print '"$((${#n}-1))"'" "$NF" "$1" "$3" "$4;exit}'
n="${n}0"
done
$ ./x5
1 184467440737990 0.00user 0:00.00elapsed 0%CPU
2 1844674407379900 0.00user 0:00.00elapsed 0%CPU
3 18446744073799512 0.00user 0:00.00elapsed 0%CPU
4 184467440737950784 0.00user 0:00.02elapsed 60%CPU
5 1844674407378830848 0.10user 0:00.22elapsed 47%CPU
6 18446744074118029312 0.94user 0:02.66elapsed 36%CPU
7 184467440723846004736 9.78user 0:24.68elapsed 40%CPU
# _
То же самое с s/gawk/mawk/:$ ./x5
1 184467440737990 0.00user 0:00.00elapsed 0%CPU
2 1844674407379900 0.00user 0:00.00elapsed 133%CPU
3 18446744073799512 0.00user 0:00.00elapsed 0%CPU
4 184467440737950784 0.00user 0:00.01elapsed 26%CPU
5 1844674407378830848 0.06user 0:00.17elapsed 38%CPU
6 18446744074118029312 0.51user 0:01.71elapsed 31%CPU
7 184467440723846004736 5.28user 0:19.83elapsed 27%CPU
у меня и %d работает в этом решении
>[оверквотинг удален]
>-1836137862
>311345785
>-1836137864
>-1444126085
>-710494993
>1436988654
>-1190184973
>
>Т.е первые два числа сложил, а потом почему-то минусы какие-то появляются
>что делаю не так?Только что наткнулся на книгу Евгения Миньковского (http://house.hcn-strela.ru/BSDCert/BSDA-course/index.html) - там и почерпнул идею :)
$ cat count
#!/bin/sh
sum=0
for num in `cat ./total.bytes`; do
sum=`echo $sum+$num | bc`
done
echo $sum
$ ./count
8510038836
Просто и эффектно. Кстати этот скрипт также будет обрабатывать числа, даже если они введены в файле через пробелы или табуляцию. А программа bc работает и с числами с десятичной точкой.
>[оверквотинг удален]
>sum=0
>for num in `cat ./total.bytes`; do
> sum=`echo $sum+$num | bc`
>done
>echo $sum
>$ ./count
>8510038836
>Просто и эффектно. Кстати этот скрипт также будет обрабатывать числа, даже если
>они введены в файле через пробелы или табуляцию. А программа bc
>работает и с числами с десятичной точкой.Блин.... только хотел написать про bc, оказалось уже в цитате написано. А если по существу, если вы покурите man bc более вдумчиво, решение выйдет еще более элегантное.
>Просто и эффектно.Ни разу не эффективно на каждое сложение запускать новый процесс bc.
Использовать bash для этой задачи вообще не эффективно, тем более, что в конечном итоге опять таки используется bc, так почему просто не привести файл в удобный для bc вид. Но если хочется:
for s in 1;do for i in `cat text` ;do echo -n "$i"+;done;echo 0;done |bc
>Использовать bash для этой задачи вообще не эффективно, тем более, что в
>конечном итоге опять таки используется bc, так почему просто не привести
>файл в удобный для bc вид. Но если хочется:
>for s in 1;do for i in `cat text` ;do echo -n
>"$i"+;done;echo 0;done |bc|*) for не нужен. back-ticks не нужен (больше ~130к файла не влезет).
Всё "как положено": awk быстрее, на bc точность не страдает...$ cat ./x6
#!/bin/bashn=10
for((i=1;i<8;i++)); do
yes | head -$n |sed 's!y!10000000000001!' | (\
{ echo "sum=0"; sed 's/.\+/sum+=\0/'; echo 'print sum," "'; } | /usr/bin/time bc) 2>&1 |awk '{print '"$((${#n}-1))"'" "$1" "$2" "$4" "$5;exit}'
n="${n}0"
done
$ ./x6
1 100000000000010 0.00user 0:00.00elapsed 0%CPU
2 1000000000000100 0.00user 0:00.00elapsed 200%CPU
3 10000000000001000 0.00user 0:00.00elapsed 100%CPU
4 100000000000010000 0.03user 0:00.05elapsed 61%CPU
5 1000000000000100000 0.36user 0:00.63elapsed 57%CPU
6 10000000000001000000 3.86user 0:06.94elapsed 56%CPU
7 100000000000010000000 39.76user 1:12.61elapsed 55%CPU
$ cat ./x6a
#!/bin/bashn=10
for((i=1;i<8;i++)); do
yes | head -$n |sed 's!y!10000000000001!' | (\
/usr/bin/time mawk 'BEGIN {c=0} {c=c+$0} END {printf("%.0f ", c)}') 2>&1 |awk '{print '"$((${#n}-1))"'" "$1" "$2" "$4" "$5;exit}'
n="${n}0"
done
$ ./x6a
1 100000000000010 0.00user 0:00.00elapsed 0%CPU
2 1000000000000100 0.00user 0:00.00elapsed 100%CPU
3 10000000000000900 0.00user 0:00.00elapsed 57%CPU
4 100000000000000912 0.00user 0:00.01elapsed 53%CPU
5 1000000000000001024 0.05user 0:00.15elapsed 38%CPU
6 10000000000000002048 0.48user 0:01.56elapsed 32%CPU
7 99999999978526310400 5.17user 0:15.50elapsed 34%CPU
$ _
>|*) for не нужен. back-ticks не нужен (больше ~130к файла не влезет).Андрей, неужели ты думаешь, что я делаю так как написал. Была мысль показать while read с перенаправлением, но ведь объяснять бы пришлось. Задача была показать в простом виде как избавится от множественных вызовов bc(или любой другой программы) в подобных случаях, как следствие внес минимум изменений в код из книжки(про умственную отсталость автора книги отдельный разговор).
Мое отношение к башу в такой задаче я в любом случае выразил однозначно.