Подсчёт времени выполнения bash-скрипта

Имеется лог куда пишется время начала и окончания работы скрипта. Всего 3 запуска в сутки, соответственно имеем 6 таймстепов. Таймстемп вида 2022-11-18T05:20:01. Задача: посчитать время работы каждого запуска в отдельности и записать это в файл. На данный момент удалось сгрепать время в виде 05:20:01 (дата в данном случае не имеет значения) и конвертировать все 6 значений в секунды.

Соответственно, теперь задача как-то вычислить разницу между вторым и первым,четвёртым и третьим, шестым и пятым, затем конвертировать в %H:%M:%S и уложить в файл. На данный момент удалось добиться вывода в файл шести значений в секундах.

Непонятно как им присвоить переменные, чтобы потом вычислить разницу, может можно как-то решить другим образом. Спасибо...

#!/bin/bash
file="time.log"
IFS=$'\n'
for var in $(grep -o '[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' $file | tail -n6)
do
echo $var | awk -F: '{ a=$1*60+$2 ; if (NF<3) print a ; else print a*60+$3 }' 
done 

Здесь выхлоп всего этого:

19201
19789
20511
21901
21901
22164

Ответы (5 шт):

Автор решения: Zt.

как-то вы сильно усложнили себе задачу

имеем 6 таймстепов. Таймстемп вида 2022-11-18T05:20:01 ... конвертировать все 6 значений в секунды

нужно просто перевести время в Unix Timestamp(Unix-время) которое уже будет в секундах, а после просто отнять Unix Time начала и конца выполнения скрипта

Получить Unix Timestamp из даты довольно просто

$ date +%s --date "2022-11-18T05:20:01"
1668741601

пример того как из лога добыть Unix Timestamp и посчитать разницу

time.log

2022-11-18T05:20:01 текст1 лога
2022-11-18T05:21:01 текст2 лога
2022-11-18T05:21:11 текст3 лога
2022-11-18T05:21:51 текст4 лога
2022-11-18T05:22:01 текст5 лога
2022-11-18T05:22:23 текст6 лога

получаем Unix Timestamp

$ awk '{system("date +%s --date "$1)}' time.log
1668741601
1668741661
1668741671
1668741711
1668741721
1668741743

с помощью awk посчитаем разницу в секундах

$ awk '{system("date +%s --date "$1)}' time.log | awk 'NR%2==1{x=$0}NR%2==0{print $0-x}'
60
40
22

с переводом итоговых секунд в формат %T, аналог %H:%M:%S

$ awk '{system("date +%s --date "$1)}' time.log |awk 'NR%2==1{x=$0}NR%2==0{system("date --utc --date=@"$0-x" +%T")}'
00:01:00
00:00:40
00:00:22

если же предполагается что работа скрипта может продлится больше чем день, то

$ awk '{system("date +%s --date "$1)}' time.log |awk 'NR%2==1{x=$0}NR%2==0{system("date --utc --date=@"$0-x" +%j.%T")}' | awk -F. '{print $1-1" дней, "$2}'
0 дней, 00:01:00
0 дней, 00:00:40
0 дней, 00:00:22
→ Ссылка
Автор решения: ipatev_nn

Предисловие:

  • В первую очередь хотелось бы отметить, что время работы скрипта лучше реализовывать в оригинальном скрипте.
  • Если это невозможно, то нужно в скрипте сбора информации о времени работы следует сделать проверку на активность основного скрипта, так как если во время выполнения будет только запись о старте, скрипт проверки времени запуска вернет не корректную информацию.

Один из вариантов решения на bash

#Входящий файл
input=file.log
#Исходящий файл
output=runtime.log
while read line; do
#Генератор, для дальнейшего получение четности строки
    i=$((${i:-0} + 1))
#Проверка генератора на целочисленное деление с остатком
    if [[ $(($i%2)) -ne 0 ]]; then
#Если остаток не равен 0, то записываем переменную запуска
        startTime=${line/ *}
    else
#Если строка четная, то проводим вычисления
#Переводим в секунды и отнимаем стоку завершения скрипта от запуска
        diffTime=$((`date -d "${line/ *}" +%s` - `date -d "${startTime}" +%s`))
#Переводим секунды и печатаем в формате: hh:mm:ss
#tee -a допишет в файл лога и выведет в консоль, если нужно просто записывать в лог, то можно использовать >>
        printf "execute time: %02d:%02d:%02d\n" "$((diffTime/3600))" "$((diffTime/60%60))" "$((diffTime%60))" | tee -a ${output}
    fi
#передаем в цикл последние 6 строк из файла
done< <(tail -n6 $input)

file.log:

2022-12-01T05:22:01 yyy
2022-12-01T05:22:23 xxx
2022-12-01T05:20:01 yyy
2022-12-05T05:21:01 xxx
2022-12-06T05:21:11 yyy
2022-12-07T05:21:51 xxx
2022-12-08T03:25:01 yyy
2022-12-08T09:55:23 xxx

output:

execute time: 96:01:00
execute time: 24:00:40
execute time: 06:30:22
→ Ссылка
Автор решения: Namerek
#!/bin/bash
intervals="00:15:12
00:04:06
00:00:50"

common_time=0

while read -r -u 3 time; do

    seconds=$(date -d "1970-01-01 $time" -u +"%s")

    common_time=$(( $common_time + $seconds ))

done 3< <(printf '%s\n' "${intervals}" )

echo $(date -d @$common_time +"%T" -u)

# 00:20:08
→ Ссылка
Автор решения: aleksandr barakin

добавлю ещё один вариант.

пусть имеется вот такая информация:

$ cat log
2022-11-18T05:20:01
2022-11-18T05:21:02
2022-11-18T05:22:01
2022-11-18T05:23:03
2022-11-18T05:24:01
2022-11-18T06:25:04

а вот однострочник, преобразующий эту информацию в требуемый формат:

$ cat log | xargs -n1 date +%s -d | sed 'N;s/\n/+/;s/^/-/' | bc | while read s; do TZ=UTC printf "%(%H:%M:%S)T\n" $s; done
00:01:01
00:01:02
01:01:03

пояснения.

для начала преобразуем в секунды с начала «unix-эпохи» (1 января 1970):

$ cat log | xargs -n1 date +%s -d
1668738001
1668738062
1668738121
1668738183
1668738241
1668741904

затем преобразуем эти шесть строк в три арифметических выражения:

$ cat log | xargs -n1 date +%s -d | sed 'N;s/\n/+/;s/^/-/'
-1668738001+1668738062
-1668738121+1668738183
-1668738241+1668741904

и вычислим эти выражения:

$ cat log | xargs -n1 date +%s -d | sed 'N;s/\n/+/;s/^/-/' | bc
61
62
3663

а полученные секунды преобразуем в часы:минуты:секунды (подсмотрел здесь):

$ cat log | xargs -n1 date +%s -d | sed 'N;s/\n/+/;s/^/-/' | bc | while read s; do TZ=UTC printf "%(%H:%M:%S)T\n" $s; done
00:01:01
00:01:02
01:01:03
→ Ссылка
Автор решения: Plastikman

В конечном итоге я взял за основу вариант @Zt. Он работает. Вот что получилось:

#!/bin/bash
log="/var/log/log.log"
output="/var/log/output.log"


# Time in seconds
timesec=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n20 | \
awk '{system("date +%s --date "$1)}' | awk 'NR==1{x=$0}NR==6{system("date --utc --date=@"$0-x" +%s")}')
echo "Full time in seconds $timesec" >> "$output"


# First run
run1start=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | awk '(NR == 1)')
echo "1'st run start $run1start" >> "$output"

run1end=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | awk '(NR == 2)')
echo "1'st run end $run1end" >> "$output"

run1=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | \
awk '{system("date +%s --date "$1)}' | awk 'NR==1{x=$0}NR==2{system("date --utc --date=@"$0-x" +%T")}')
echo "1'st run duration: $run1" >> "$output"


# Second run
run2start=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | awk '(NR == 3)')
echo "2'nd run start $run2start" >> "$output"

run2end=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | awk '(NR == 4)')
echo "2'nd run end $run2end" >> "$output"

run2=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | \
awk '{system("date +%s --date "$1)}' | awk 'NR==3{x=$0}NR==4{system("date --utc --date=@"$0-x" +%T")}')
echo "2'nd run duration: $run2" >> "$output"

# Third run duration
run3start=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | awk '(NR == 5)')
echo "3'rd run start $run3start" >> "$output"

run3end=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | awk '(NR == 6)')
echo "3'rd run end $run3end" >> "$output"

run3=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | \
awk '{system("date +%s --date "$1)}' | awk 'NR==5{x=$0}NR==6{system("date --utc --date=@"$0-x" +%T")}')
echo "3'rd run duration: $run3" >> "$output"

# Time of run
run=$(grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}T[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}' "$log" | tail -n6 | \
awk '{system("date +%s --date "$1)}' | awk 'NR==1{x=$0}NR==6{system("date --utc --date=@"$0-x" +%T")}')
echo "Total runs duration: $run" >> "$output"

→ Ссылка