Bash Script to Calculate Time Elapsed

Bash script to calculate time elapsed

Either $(()) or $[] will work for computing the result of an arithmetic operation. You're using $() which is simply taking the string and evaluating it as a command. It's a bit of a subtle distinction. Hope this helps.

As tink pointed out in the comments on this answer, $[] is deprecated, and $(()) should be favored.

How to calculate time elapsed in bash script?

Bash has a handy SECONDS builtin variable that tracks the number of seconds that have passed since the shell was started. This variable retains its properties when assigned to, and the value returned after the assignment is the number of seconds since the assignment plus the assigned value.

Thus, you can just set SECONDS to 0 before starting the timed event, simply read SECONDS after the event, and do the time arithmetic before displaying.

#!/usr/bin/env bash

SECONDS=0
# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."

As this solution doesn't depend on date +%s (which is a GNU extension), it's portable to all systems supported by Bash.

Shell script to calculate time elapsed

The output of time goes to stderr. You have to redirect it.

TIMEFORMAT=%R
r=$( { time /home/pop/Daa/./a.out; } 2>&1 )

And you can't have spaces around the equal sign. It is preferable to use $() instead of backticks since it's easier to read, there's no confusion with single quotes and it's easier to nest them.

Adjust elapsed time for 5 hours?

You can use bash regular expression to get different components :

#!/bin/bash

PROC_NAME=my_proc_name

# Get all PIDs for process name
procs=(`ps aux | grep $PROC_NAME | awk '{print $2}'`)

pattern='((.*)-)?((..):)?(..):(..)'

for pid in ${procs[@]}; do
if [[ "$(ps -o etime= -p $pid)" =~ $pattern ]] && {
[ -n "${BASH_REMATCH[2]}" ] || # if day component exists, then it's more than 5 hours
{ [ -n "${BASH_REMATCH[4]}" ] && ((10#${BASH_REMATCH[4]} >= 5)); } }; then
echo kill -9 $pid
fi
done

Remove echo (dry run) if you see the result is expected.

Explanation of pattern='((.*)-)?((..):)?(..):(..)' :

1) ((.*)-)? means optional day component
if present like 9- then ${BASH_REMATCH[1]} = 9-, ${BASH_REMATCH[2]} = 9
if absent, ${BASH_REMATCH[2]} is empty
2) ((..):)? means optional hour component
if present like 05 then ${BASH_REMATCH[3]} = 05:,${BASH_REMATCH[4]} = 05
if absent, ${BASH_REMATCH[4]} is empty

Bash: Calculate the time differences in hours from input like YYYYMMDDHH

For performance reasons we want to limit the number of sub-process calls we need to invoke:

  • use bash substring functionality to convert inputs into usable date/time strings
  • use bash math to replace bc call

bash substring functionality to break the inputs into a usable date/time format, eg:

# convert to usable date/time format:

$ start_date=1996010100
$ echo "${start_date:0:4}-${start_date:4:2}-${start_date:6:2} ${start_date:8:2}:00:00"
1996-01-01 00:00:00

# convert to epoch/seconds:

$ start=$(date -d "${start_date:0:4}-${start_date:4:2}-${start_date:6:2} ${start_date:8:2}:00:00" +"%s")
$ echo $start
820476000

Applying to ${end_date} and using bash math:

$ end_date=1996010122
$ end=$(date -d "${end_date:0:4}-${end_date:4:2}-${end_date:6:2} ${end_date:8:2}:00:00" +"%s")
$ echo $end
820555200

$ hours=$(( (end - start) / 3600))
$ echo $hours
22

This leaves us with 2 sub-process calls ($(date ...)). While other languages/tools (awk, perl, etc) can likely speed this up a bit, if you need to store the result in a bash variable then you're looking at needing at least 1 sub-process call (ie, hours=$(awk/perl/??? ...)).

If performance is really important (eg, needing to perform this 1000's of times) take a look at this SO answer that uses a fifo, background date process and io redirection ... yeah, a bit more coding and a bit more convoluted but also a bit faster for large volumes of operations.

how to calculate total elapsed time

Limitation of this solution: Max 23 hours. For more, days need to be added.

StartTime="June 3, 2019 at 2:50:02 am"
EndTime="June 3, 2019 at 5:06:40 am"
StartTimeInEpoch=`echo $StartTime | sed 's/at //g' | date -f- +"%s"`
EndTimeInEpoch=`echo $EndTime | sed 's/at //g' | date -f- +"%s"`
echo $EndTimeInEpoch-$StartTimeInEpoch | bc | sed 's/^/@/g' | date -u -f- "+%_H hours %_M minutes %_S seconds"

Output:

2 hours 16 minutes 38 seconds

Assuming you've got your dates in variables StartTime and EndTime. It's necessary to remove at from them, sed do this. Then both dates are converted to epoch time +"%s" do the trick. -f- tells date to take date from stdin (pipe). Then we can subtract the dates, add @ to the beginning and format with date. -u mean UTC time - no time shift.



Related Topics



Leave a reply



Submit