The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Сложить массив чисел на bash, !*! Stone, 27-Фев-09, 15:06  [смотреть все]
Есть файл вида

$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

Т.е первые два числа сложил, а потом почему-то минусы какие-то появляются
что делаю не так?

  • Сложить массив чисел на bash, !*! vic, 15:25 , 27-Фев-09 (1)
    >Есть файл вида
    >
    >$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

    • Сложить массив чисел на bash, !*! vic, 15:45 , 27-Фев-09 (2)
      а еще лучше так
      result=`sum=0 ; (while read num; do sum=$(echo "$sum+$num" | bc -q); done ; echo $sum) < total.bytes`
      echo $result

      • без цикла, !*! Andrey Mitrofanov, 17:01 , 27-Фев-09 (10)
        $ cat total.bytes
        1962647280
        154580283
        85368270
        256233601

        2448176455
        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
        $ _

        • без цикла, !*! Stone, 17:13 , 27-Фев-09 (13)
          >[оверквотинг удален]
          >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 выдает

        • без цикла, !*! vic, 17:14 , 27-Фев-09 (14)
          >[оверквотинг удален]
          >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 отвалится

          • без цикла, !*! Stone, 17:20 , 27-Фев-09 (16)

            >как бы bc не отвалился, хз сколько там чисел
            >echo `cat total.bytes` | tr " " "+" | bc
            >это все хорошо, а если там чисел столько что bc отвалится

            Во, самый короткий вариант, и работает в баше и в sh!!!

          • без цикла, !*! vic, 17:21 , 27-Фев-09 (17)
            >[оверквотинг удален]
            >>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 отвалится

            какая настойчивая мысль....)))))))))

          • с бенчмарками :), !*! Andrey Mitrofanov, 19:56 , 02-Мрт-09 (18)
            >>$ ( 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/bash

            n=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($числа_слагаемых), вторая - "длинна" суммы.

            • и, кстати, 'больше' не работает :/, !*! Andrey Mitrofanov, 18:22 , 28-Май-09 (24)
              >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 и вообще не работает...

    • Сложить массив чисел на bash, !*! Stone, 15:47 , 27-Фев-09 (3)
      >[оверквотинг удален]
      >>256233601
      >>2448176455
      >>3211021168
      >>392011779
      >
      >в минус уходит из-за переполнения int.
      >
      >попробуйте так:
      >sum = 0; cat total.bytes | while read num ; do sum=`echo
      >$sum+$num" | bc -q` ; done ; echo $sum

      Тоже подумал что от переполнения, но когда сложил вручную несколько первых чисел, но все нормально

      Ваш скрипт к сожалению не работает, там вроде кавычки забыли, я поставил, все равно не пашет

      • Сложить массив чисел на bash, !*! Stone, 15:51 , 27-Фев-09 (4)
        >[оверквотинг удален]
        >>
        >>попробуйте так:
        >>sum = 0; cat total.bytes | while read num ; do sum=`echo
        >>$sum+$num" | bc -q` ; done ; echo $sum
        >
        >Тоже подумал что от переполнения, но когда сложил вручную несколько первых чисел,
        >но все нормально
        >
        >Ваш скрипт к сожалению не работает, там вроде кавычки забыли, я поставил,
        >все равно не пашет

        А вот второй скрипт пашет, спасибо!

  • Сложить массив чисел на bash, !*! allez, 15:56 , 27-Фев-09 (5)
    >#!/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


    • Сложить массив чисел на bash, !*! Stone, 16:11 , 27-Фев-09 (6)
      >[оверквотинг удален]
      >while read line;
      >do
      >  let y=$y+$line;
      >done < total.bytes
      >echo $y
      >
      >$ ./script.sh
      >8510038836
      >
      >

      Так тоже минусы выводит у меня!

      • Сложить массив чисел на bash, !*! vic, 16:39 , 27-Фев-09 (7)
        >[оверквотинг удален]
        >>  let y=$y+$line;
        >>done < total.bytes
        >>echo $y
        >>
        >>$ ./script.sh
        >>8510038836
        >>
        >>
        >
        >Так тоже минусы выводит у меня!

        А вы cat | while делаете или while .. done < file ?
        В первом случае может неявно вызываться субшелл и как следствие переменная y может быть не видна т.к ее область видимости - субшелл, отсюда глюки.

        Что за система? (uname -a && sh --version) ?

        • Сложить массив чисел на bash, !*! Stone, 16:46 , 27-Фев-09 (8)

          >А вы 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, !*! Stone, 16:47 , 27-Фев-09 (9)
            О, а если 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, !*! vic, 17:04 , 27-Фев-09 (11)
              >О, а если bash поставить, то работает!Дело в sh значит

              однако суровый sh в freebsd :))

              result=`y=0; (while read line; do let y=$y+$line; done ; echo $y) < total.bytes`
              echo $result

              что буит?


              • Сложить массив чисел на bash, !*! Stone, 17:09 , 27-Фев-09 (12)
                >>О, а если 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?и его вообще можно обновить, в портах нету его

                • Сложить массив чисел на bash, !*! vic, 17:19 , 27-Фев-09 (15)
                  >Тож самое, минусы.А как узнать версию sh?и его вообще можно обновить, в
                  >портах нету его

                  уже можно не парится, итак видно что суровый :)
                  а минусы это переполнение (ибо сурово), поэтому во втором варианте я и предложил bc :)

              • Сложить массив чисел на bash, !*! 0dmin, 23:00 , 03-Мрт-09 (22)
                >>О, а если bash поставить, то работает!Дело в sh значит
                >однако суровый sh в freebsd :))

                Номальный POSIX Shell.

                PS: А да - во фряхе _внезапно!_ bash зовётся bash'ем а не sh :)

  • Сложить массив чисел на bash, !*! andreik, 16:31 , 03-Мрт-09 (19)
    awk 'BEGIN {c=0} {c=c+$0} END {printf("%.0f\n", c)}' total.bytes
    • Сложить массив чисел на bash, !*! Andrey Mitrofanov, 18:04 , 03-Мрт-09 (20)
      >awk 'BEGIN {c=0} {c=c+$0} END {printf("%.0f\n", c)}' total.bytes

      Если точности плавающих - хватает, то да, так быстрее:

      $ cat ./x5
      #!/bin/bash

      n=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

  • Сложить массив чисел на bash, !*! krigs, 03:31 , 25-Май-09 (23)
    >[оверквотинг удален]
    >-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 работает и с числами с десятичной точкой.

    • Сложить массив чисел на bash, !*! Andrew, 23:57 , 29-Май-09 (25)
      >[оверквотинг удален]
      >sum=0
      >for num in `cat ./total.bytes`; do
      >    sum=`echo $sum+$num | bc`
      >done
      >echo $sum
      >$ ./count
      >8510038836
      >Просто и эффектно. Кстати этот скрипт также будет обрабатывать числа, даже если
      >они введены в файле через пробелы или табуляцию. А программа bc
      >работает и с числами с десятичной точкой.

      Блин.... только хотел написать про bc, оказалось уже в цитате написано. А если по существу, если вы покурите man bc более вдумчиво, решение выйдет еще более элегантное.

    • Сложить массив чисел на bash, !*! anonymous, 06:01 , 30-Май-09 (26)
      >Просто и эффектно.

      Ни разу не эффективно на каждое сложение запускать новый процесс bc.

      • Сложить массив чисел на bash, !*! angra, 08:28 , 31-Май-09 (27)
        Использовать bash для этой задачи вообще не эффективно, тем более, что в конечном итоге опять таки используется bc, так почему просто не привести файл в удобный для bc вид. Но если хочется:
        for s in 1;do for i in `cat text` ;do echo -n "$i"+;done;echo 0;done |bc
        • а сертифицированные BSDA читают книги, !*! Andrey Mitrofanov, 17:25 , 01-Июн-09 (28)
          >Использовать 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/bash

          n=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/bash

          n=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
          $ _

          • а сертифицированные BSDA читают книги, !*! angra, 00:52 , 02-Июн-09 (29)
            >|*) for не нужен. back-ticks не нужен (больше ~130к файла не влезет).

            Андрей, неужели ты думаешь, что я делаю так как написал. Была мысль показать while read с перенаправлением, но ведь объяснять бы пришлось. Задача была показать в простом виде как избавится от множественных вызовов bc(или любой другой программы) в подобных случаях, как следствие внес минимум изменений в код из книжки(про умственную отсталость автора книги отдельный разговор).
            Мое отношение к башу в такой задаче я в любом случае выразил однозначно.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру