Як підбити підсумок за допомогою bash?


12

Хочу знати, скільки часу в моєму комп’ютері знадобиться серія процесів, щоб вирішити, чи варто мені працювати там чи на більш сильному комп'ютері. Отже, я прогнозую час виконання кожної команди. Вихід виглядає так:

process1    00:03:34
process2    00:00:35
process3    00:12:34

Як я можу підбити підсумки другого стовпця, щоб отримати загальний час роботи? Я міг би спробувати пропустити кожен рядок

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

але це не має сенсу, оскільки значення не є натуральними числами.

Відповіді:


15
#!/bin/sh

EPOCH='jan 1 1970'
sum=0

for i in 00:03:34 00:00:35 00:12:34
do
  sum="$(date -u -d "$EPOCH $i" +%s) + $sum"
done
echo $sum|bc

date -u -d "jan 1 1970" +%sдає 0. Так date -u -d "jan 1 1970 00:03:34" +%sдає 214 сек.


Здається, трохи хак-у, але ей, це працює цікавим (начебто) способом.
hjk

4

Якщо припустити, що ви використовуєте команду bash 'time' вбудований, перед запуском програми ви можете export TIMEFORMAT=%0R. Тоді результат буде цілими секундами дозволеним awk. Більше інформації можна знайти в розділі «Змінні оболонки» на сторінці bash man.


4

Якщо ви не можете (або не хочете) використовувати TIMEFORMATпросто необхідність перенести час на секунди, то додайте їх разом. Наприклад, вихід труби через:

{                                           
sum=0
while IFS="[ :]" proc_name h m s
do
    let sum+=$((60*($m+60*$h)+$s)) 
done 
echo $sum  
} 

Або якщо ви хочете, можете обмінятися останнім echo-командом

printf "%02d:%02d:%02d\n" $[sum/3600] $[sum/60] $[sum%60]

Протягом декількох хвилин слід $[sum/60%60]позбавити годин.
Джессі Чизгольм

3

Оновлення:

Ось нова реалізація, яка використовує dc"вихідну базу". Зауважте, що якщо загальна сума більше 60 годин, це виведе чотири розділені пробіли значення замість трьох. (І якщо загальна сума менше однієї години, виведеться лише два значення, розділені пробілом.)

awk '{print $2}' file.txt | tr : \ | dc -f - -e '60o0ddd[+r60*+r60d**+z1<a]dsaxp'

Вхідні дані приймаються у тричі години, хвилини, секунди, як показано в питанні.

Вихід на поданий вхід:

 16 43

Оригінальна відповідь:

Давайте зробимо це з dcвашим настільним калькулятором. Це задній край bc, і він надзвичайно гнучкий, хоча часто вважається виразним.


По-перше, деяка попередня обробка, щоб дати часу лише та перетворити колонки в пробіли:

awk '{print $2}' | tr : ' '

Ми також могли б зробити це за допомогою Sed:

sed -En -e 's/^.*([0-9][0-9]):([0-9][0-9]):([0-9][0-9]).*$/\1 \2 \3/p'

Я піду з Awk і trтому, що це простіше. Будь-яка з вищевказаних команд видає чистий вихід у наступному форматі. (Я використовую власний приклад тексту, тому що вважаю його більш цікавим; він включає години. Також будуть працювати і ваші.)

$ cat input
9 39 42
8 04 50
7 49 32
10 01 54
7 19 18

Зазначені рази у наведеному вище форматі, запустіть їх через наступний скрипт Sed і передайте результат, dcяк показано:

sed -e '1s/^/0 /' -e 's/$/ r 60 * + r 60 60 * * + +/' -e '$s/$/ 60 60 * ~ 60 ~ f/' input | dc

(Розбито вниз, щоб зменшити прокрутку в бік :)

sed <input \
    -e '1s/^/0 /' \
    -e 's/$/ r 60 * + r 60 60 * * + +/' \
    -e '$s/$/ 60 60 * ~ 60 ~ f/' |
      dc 

Вихід буде у цій послідовності секундами, хвилинами, годинами. (Зауважте, це зворотна послідовність.) Я просто навчаюся, dcтому це не ідеальне рішення, але я думаю, що це досить добре для першого погляду dc.

Приклад введення та виводу, вставлений безпосередньо з мого терміналу:

$ cat input 
9 39 42
8 04 50
7 49 32
10 01 54
7 19 18
$ sed -e '1s/^/0 /' -e 's/$/ r 60 * + r 60 60 * * + +/' -e '$s/$/ 60 60 * ~ 60 ~ f/' input | dc 
16
55
42
$ 

2

Ось моє рішення - використання split(). Друк загального часу в секундах:

awk '{
        split($2, tm, ":");
        tottm += tm[3] + tm[2] * 60 + tm[1] * 3600;
    }
    END {
        print tottm;
    }' ptime

Друк у приємному форматі часу:

awk '{
        split($2, tm, ":");
        secs += tm[3]; 
        mins += tm[2] + int(secs / 60); 
        hrs += tm[1] + int(mins / 60);
        secs %= 60; mins %= 60;
    }
    END {
        printf "%d:%d:%d\n", hrs, mins, secs;
    }' ptime

GNU awk також підтримує стрімкінг, але він буде використовувати ваш поточний часовий пояс, тому результати будуть заплутаними.


Ви можете зателефонувати gawkз , TZ=UTC0 gawk...щоб зняти питання часового поясу.
Стефан Шазелас


0

Варіації за темами тут, але більше труб

echo """
process1    00:03:34
process2    00:00:35
process3    00:12:34
"""  | \
     sed 's/process.  *\([0-9]\)/\1/g' | \
     xargs -i{} date +%s --date "1970-1-1 {}" | \
     awk '{sum += $1; cnt +=1} 
         END {
               print sum / 60, " total minutes processing";
               print (sum / 3600) / cnt, "minutes per job"
         }'
916.717  total minutes processing
5.09287 minutes per job

0

Майже будь-яка оболонка могла б зробити математику:

#!/bin/sh

IFS=:; set +f
getseconds(){ echo "$(( ($1*60+$2)*60+$3 ))"; }

for   t in 00:03:34 00:00:35 00:12:34
do    sum=$((sum + $(getseconds $t) ))
done
printf '%s\n' "$sum"

Використовуйте getseconds $=tв zsh, щоб змусити його розщеплюватися.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.