Regex to validate parameter for sleep

I'm trying to use a regular expression to validate a value for sleep entered by the user. The test should fail all negative values and 0 but let pass all combinations of + . and digits that would amount to a valid parameter for sleep.
Examples for valid: 1, 1.5, .5, 0.5, +1, +.5, +1.3 etc.
Examples for invalid: 0, .0, 0., 0.0, +0, +.0, +0, +0.0 etc. and any string starting with a -

I wrote a small program to test the regular expressions I'm using now - two expressions combined in a test statement. While looking a bit contrived they almost do the job except that strings like .1.1 still pass the test as valid.

Can someone help me take the final step?

#!/bin/bash

if [ $# -gt 0 ] ; then # user entered parameter for sleep
   # check fails if it's not a positive floating point number
   if ! [[ $1 =~ ^\+?\.?[0-9]+\.?[0-9]*$ ]] || [[ $1 =~ ^[\+-]?0?\.?0*$ ]]; then
      echo invalid value for sleep: $1
   else
     echo valid: $1
   fi
fi

Thanks.

------ Post updated at 01:08 PM ------

I found a solution by adding an && clause to the if condition:

if ! [[ $1 =~ ^\+?\.?[0-9]+\.?[0-9]*$ ]] || [[ $1 =~ ^[\+-]?0?\.?0*$ ]] && ! [[ $1 =~ ^\.*$ ]

but it looks even more contrived now.

Is there a way to solve the problem within one regular expression? Or something much shorter? (I'm not overly familiar with regular expressions and I expect an expert to come up easily with something shorter, humiliatingly shorter.)

------ Post updated at 01:10 PM ------

OMG. There's a ] missing at the end.

Would this come close?

sed -r '/-/bW; /[1-9]/ {s/$/\tOK/; b}; :W; s/$/\tWRONG/' file
1       OK
1.5     OK
.5      OK
0.5     OK
+1      OK
.50     OK
0.5000  OK
+100    OK
+.5     OK
+1.3    OK
-1      WRONG
-.5     WRONG
-1.3    WRONG
.0      WRONG
0.      WRONG
0.0     WRONG
+0      WRONG
+.0     WRONG
+0      WRONG
+0.0    WRONG

As close as I am now. But the same numbers still slip through.

With this in 'file':

1
1.5
.5
.0.5
.1.1
.1.3.5

I get this output:

1	OK
1.5	OK
.5	OK
.0.5	OK
.1.1	OK
.1.3.5	OK

The last two are definitely not ok as parameter to sleep.

And how would I use the sed test in the script in place of the regular expression?

------ Post updated at 02:42 PM ------

This is the output I would need to see:

1       OK
1.0     OK
.1      OK
0.1     OK
+1      OK
+1.0    OK
+.1     OK
-1      WRONG
-1.0    WRONG
-.1     WRONG
0       WRONG
-0      WRONG
+0      WRONG
.0      WRONG
-.0     WRONG
+.0     WRONG
0.0     WRONG
-0.0    WRONG
+0.0    WRONG

And how would I use sed as a substitute for the regular expression in the if statement in my original post?

OK, multiple dots, and any non-numeric characters discriminated as well:

sed -r '/[^0-9+.]/bW; /([.]).*\1/bW; /[1-9]/ {s/$/\tOK/; b}; :W; s/$/\tWRONG/' file
1       OK
1.5     OK
.5      OK
0.5     OK
+1      OK
.50     OK
0.5000  OK
+100    OK
+.5     OK
+1.3    OK
0.5a000 WRONG
+100b   WRONG
+.5;    WRONG
+z1.3   WRONG
-1      WRONG
-.5     WRONG
-1.3    WRONG
.0      WRONG
0.      WRONG
0.0     WRONG
+0      WRONG
+.0     WRONG
+0      WRONG
+0.0    WRONG
.0.5    WRONG
.1.1    WRONG
.1.3.5  WRONG

You could run the sed with a "here-string" like

$ set -- .1.3.5
$ sed -r '/[^0-9+.]/bW; /([.]).*\1/bW; /[1-9]/ {s/$/\tOK/; b}; :W; s/$/\tWRONG/' <<< $1
.1.3.5    WRONG

And then parse the sed output for the word 'WRONG' or 'OK'?

It would work but it it's not very elegant, kind of overkill.

I think the best way is to let the original if statement do the entire job. I just need to give it the right regex (or something else) to work on.

And I'd really like to get the regex right. :slight_smile:

$ if sed -r '/[^0-9+.]|([.]).*\1/q1; /[1-9]/q0; q1' <<< $1
     then echo valid: $1
     else echo invalid value for sleep: $1
  fi 
1 Like

I'm impressed (though after running the code I think the then and else sections should be reversed - see below.)

I admit I'll have to spend a day with sed one of these days and I will, but just assuming all is well - and it looks like it is - what's the exit status of sed used by if here?

According to sed documentation sed returns 0 on successful completion and 1 if it encounters an invalid command, invalid syntax. The latter doesn't seem to be the case here.

In your code it looks like sed returns 0 for a valid value and 1 for an invalid one.

With tplus being (then/else reversed and echo $? added by me):

if sed -r '/[^0-9+.]|([.]).*\1/q1; /[1-9]/q0; q1' <<< $1
   then echo exit status: $?; echo valid: $1
else 
   echo exit status: $?; echo invalid: $1
fi

this is the output I get:

$ bash tplus 0
0
exit status: 1
invalid: 0
$ bash tplus 1
1
exit status: 0
valid: 1
$ 

And... er... do you have a suggestion how to do it in a naked regular expression within [[ ... ]], without using sed or another program?

man sed :

q0 and q1 in above script set the exit code to be evaluated in the if ... fi construct.

Wouldn't it be the time NOW to analyse the regex used in the sed script and try to transform / translate it to a bash regex?

Howsoever, with some experimenting, I found

while read DA
  do   if [[ "$DA" =~ [^0-9+.]|^[+0.]*$|[.].*[.] ]]
          then echo invalid value for sleep: $DA, $?, ${BASH_REMATCH[0]}
          else echo valid: $DA, $?, ${BASH_REMATCH[0]}
       fi
  done < file

to come close to what you want / need.

1 Like

That's what I thought, too but it was late and I thought it wouldn't hurt to ask, maybe you or somebody had a quick answer to this. I certainly didn't want you to spend time experimenting.

I'll spend some time to solve the rest myself.

Thanks a lot.

Glad it helped. And, I like experimenting, so don't worry. You're welcome.