Re: Is there a POSIX compliant way of turning a "HH:MM:SS" formatted string to seconds? ...
On Sun, Jul 20, 2025 at 09:02:37 +0700, Max Nikulin wrote:
> I have no idea to which degree the following is portable:
>
> strip_zeroes() { zeroes="${1%%[!0]*}"; printf '%s\n' "${1#"$zeroes"}"; }
That's POSIX compliant. It's very similar to the first examples on
<https://mywiki.wooledge.org/BashFAQ/067>:
# POSIX
junk=${var%%[! ]*} # remove all but leading spaces
var=${var#"$junk"} # remove leading spaces from original string
junk=${var##*[! ]} # remove all but trailing spaces
var=${var%"$junk"} # remove trailing spaces from original string
I have a strong dislike for functions that "return" things by writing
to stdout, and expect you to capture that output using a command
substitution, because every command substitution creates a forked process.
Not to mention the fact that command substitution alters the captured
output (by stripping all trailing newlines).
But that's just me. I know that functions writing to stdout are
considered "normal" in sh scripting, and that I'm fighting an uphill
battle.
> However what
> I am really afraid of is
>
> https://mywiki.wooledge.org/BashPitfalls#pf46
> > 46. read num; echo $((num+1))
> >
> > Always validate your input (see BashFAQ/054) before using num in an arithmetic context as it allows code injection.
> >
> > $ echo 'a[$(echo injection >&2)]' | bash -c 'read num; echo $((num+1))'
> > injection
> > 1
Yes. Bash is a complete disaster when it comes to safety.
To avoid code injections, you always have to look at your input sources
and decide how trustworthy they are. If your input source is $(date +%d)
or something similar, you can be pretty sure it won't ever give you
unsafe values. But if you're reading input from a user, you'll want to
validate it before you do anything else.
And make sure your validation is stringy, *NOT* something mathy like:
[[ $x = $((x)) ]] || die "..."
Examples of acceptable validation:
[[ $x = +([0-9]) ]] || die "input must be a number"
hmsglob='+([0-9]):[0-9][0-9]?(:[0-9][0-9])'
[[ $input = $hmsglob ]] || die "input must be M:SS or H:MM:SS"
> JavaScript (browser dev tools console)
> 009 === 9 // => true
> parseInt("009") // => 9
> 010 === 8 // => true
> parseInt("010") // => 10
I won't even ask.
Reply to: