The original
https://lists.debian.org/debian-user/2025/07/msg00407.html
specified HH:MM:SS format for input, nothing more, nothing
less.  And sure, we should validate input and, e.g. throw error if input
isn't valid.  But if we want to accept additional, well, that should
also be in the earlier specification.  Also, the earlier context,
YouTube video durations, also not likely we'll be dealing
with > 99H 59M 59S video durations.   And quick search seems to suggest
YouTube currently has a max. video duration of 12 hours.

And sed and awk are POSIX, so using those is POSIX, so long as we
restrict ourselves to specified POSIX functionality.

And  yes, could do it entirely within POSIX shell, no external
commands/programs at all, though that may be fair bit more code.
Others have suggested, e.g. python.  Certainly python or perl or the
like could be used, code would be more concise, but system overhead
would generally be significantly larger.  sed and awk are comparatively
lightweight, and quite POSIX, though not as system efficient as doing it
only within the shell itself, at least presuming we're already in a
POSIX (capable) shell context.

I also left out input validation in the interests of brevity, but of
course that's easy to add.  A more complete POSIX compliant example:

#!/bin/sh

# Take our HH:MM:SS format 1st and only argument,
# convert to seconds and write that to stdout.

set -e

LC_ALL=C export LC_ALL

# [ test is not guaranteed to be built-in to POSIX shell, so we'll try
# to stick to what must be internal only.
# same applies to echo (plus its other (potential) issues)

case "$# $1" in
  1\ [0-9][0-9]:[0-9][0-9]:[0-9][0-9])
    :
  ;;
  *)
    1>&2 printf '%s\n' \
      "${0##*/}: usage, requires single argument in format HH:MM:SS, aborting"
    exit 1
  ;;
esac
h=${1%%:*}
h=${h#0}
hm=${1%:*}
m=${hm#*:}
unset hm
m=${m#0}
s=${1##*:}
s=${s#0}
printf '%s\n' $((3600 * h + 60 * m + s))

Of course in the original post, more full context wasn't mentioned.
So, e.g., did they want a separate standalone program for this?
Or were they wanting to do it in existing POSIX shell program, or
perhaps even existing interactive POSIX shell session.

In that case they may want something a simple as a copy-paste one-liner
that they could then easily reuse from shell history for some convenient
bit.

(hhmmss=09:08:07; set -e; LC_ALL=C export LC_ALL; case "$hhmmss" in
[0-9][0-9]:[0-9][0-9]:[0-9][0-9]) :;; *) exit 1;; esac;
h=${hhmmss%%:*}; h=${h#0}; hm=${hhmmss%:*}; m=${hm#*:}; unset hm;
m=${m#0}; s=${hhmmss##*:}; s=${s#0}; printf '%s\n' $((3600 * h + 60 *
m + s)))

Or maybe they'd want to add similar to an existing POSIX shell program,
with bit of suitable reformatting, and replace the exit 1 with return 1
within a function, or some more suitable/complete error handling, and
perhaps augment the set -e with some more general error trapping and
handling via trap.


On Sat, Jul 19, 2025 at 5:26 AM Greg Wooledge <g...@wooledge.org> wrote:
> On Fri, Jul 18, 2025 at 21:08:09 -0700, Michael Paoli wrote:
> > echo \
> > $((
> >   $(
> >     d12='\([0-9]\{1,2\}\)'
> >     echo 09:10:11 |
> >   sed -e '
> >     s/^/ /
> >     s/:/ /g
> >     s/ 0*\([0-9]\)/ \1/g
> >   '"  s/^ $d12 $d12 $d12"'$/3600 * \1 + 60 * \2 + \3/
> >   '
> >   )
> > ))
>
> I don't like this one as much.  It's better than the original one-liner
> (both because it's actually correct -- I think! -- and because it's in
> a format that's a little bit easier to read), but it still looks like
> it was written by someone who is bound and determined to use sed for this,
> no matter how difficult it may be.
>
> Also, the use of [0-9]\{1,2\} for the first segment means you're
> hard-capping this to 99:59:59 and will never be able to handle 100:23:45.
> That might be OK, or not.  I don't know whether there are any restrictions
> on the durations the OP is dealing with.  I would've used \{1,\} to
> remove the two-digit limit, if I had to do it this way.

Reply via email to