Подсчёт времени выполнения 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 шт):
как-то вы сильно усложнили себе задачу
имеем 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
Предисловие:
- В первую очередь хотелось бы отметить, что время работы скрипта лучше реализовывать в оригинальном скрипте.
- Если это невозможно, то нужно в скрипте сбора информации о времени работы следует сделать проверку на активность основного скрипта, так как если во время выполнения будет только запись о старте, скрипт проверки времени запуска вернет не корректную информацию.
Один из вариантов решения на 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
#!/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
добавлю ещё один вариант.
пусть имеется вот такая информация:
$ 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
В конечном итоге я взял за основу вариант @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"