To complement Matt Jacob's elegant perl
solution with a (POSIX-compliant) awk
solution:
awk -F: '{ n=0; for(i=NF; i>=1; --i) secs += $i * 60 ^ n++ } END { print secs }' file
With the sample input, this outputs (the sum of all time spans in seconds):
3724.33
See the section below for how to format this value as a time span, similar to the input (01:02:04.33
).
Explanation:
-F:
splits the input lines into fields by :
, so that the resulting fields ($1
, $2
, ...) represent the hour, minute, and seconds components individually.
n=0; for(i=NF; i>=1; --i) secs += $i * 60 ^ n++
enumerates the fields in reverse order (first seconds, then minutes, then hours, if defined; NF
is the number of fields) and multiplies each field with the appropriate multiple of 60 to yield an overall value in seconds, stored in variable secs
, cumulatively across lines.
END { print secs }
is executed after all lines have been processed and simply prints the cumulative value in seconds.
Formatting the output as a time span:
Custom output formatting must be used:
awk -F: '
{ n=0; for(i=NF; i>=1; --i) secs += $i * 60 ^ n++ }
END {
hours = int(secs / 3600)
minutes = int((secs - hours * 3600) / 60)
secs = secs % 60
printf "%02d:%02d:%05.2f\n", hours, minutes, secs
}
' file
The above yields (the equivalent of 3724.33
seconds):
01:02:04.33
The END { ... }
block splits the total number of seconds accumulated in secs
back into hours, minutes, and seconds, and outputs the result with appropriate formatting of the components using printf
.
The reason that utilities such as date
and GNU awk
's (nonstandard) date-formatting functions cannot be used to format the output is twofold:
The standard time format specifier %H
wraps around at 24 hours, so if the cumulative time span exceeds 24 hours, the output would be incorrect.
Fractional seconds would be lost (the granularity of Unix time stamps is whole seconds).