0

Suppose I have the following script saved as runme.sh

usage() { echo "Usage: $0 [-s <integer>] [-l <string>]" 1>&2; exit 1; }

while getopts ":s:l:" o; do
    case "${o}" in
        s)  s=${OPTARG}
            [[ $s =~ ^-?[0-9]+$ ]] || usage ;;
        l)  l=${OPTARG} ;;
        *)  usage ;;
    esac
done
echo "s = ${s}"
echo "p = ${p}"

This gives output as follows:

$ ./runme.sh -s x -l hello
Usage: ./runme.sh [-s <integer>] [-l <string>]
$ ./runme.sh -s 1 -l hello
s = 1
l = hello

Now compare this to the top answer from this thread. This latter script seems to run the same whether we have:

((s == 45 || s == 90))

or

(($s == 45 || $s == 90))

at line nine...

However, for my script I need the '$' in front of the s variable, or else it only gives the first output shown above, regardless of whether s is an integer. Why is this? I would assume it has something to do with the difference between [[ and (( but I can't seem to find a definitive answer.

Community
  • 1
  • 1
ajkal
  • 3
  • 1
  • Did I modify the title in a way that more accurately reflects your original question? (If so, the body text could probably be considerably shortened; likewise, I'm unclear on what getopts has to do with the question, since conditionals work the same way whether or not it's getopts providing values). – Charles Duffy Mar 10 '15 at 00:45
  • Yes, thank you very much! That's the gist of what I was asking. I wasn't aware of the difference in behavior for (( vs. [[ that you mention below. I figured it was something rather basic, but I also thought it might be something specific to the getopts routine I was using. – ajkal Mar 10 '15 at 23:31

1 Answers1

3

(( )) is a math context; explicit $s aren't needed in a math context (since nothing but numbers are valid there, any token started with a non-numeric character can be assumed to be a variable name -- and will be treated as 0 should that variable be nonexistent/empty), but are needed everywhere else (since anywhere else, a could mean the literal character a, rather than meaning $a).


To reiterate:

[[ $s =~ ^-?[0-9]+$ ]]

...asks whether the value in $s matches the regex.


[[ s =~ ^-?[0-9]+$ ]]

...asks whether the letter s matches the regex.


(( s == 0 ))

...is by its nature a numeric comparison, and so can (since s isn't a number) look up the value of $s with confidence that no other meaning would be plausible.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • 1
    This is complicated by the behavior of arithmetic operators in `[[` which *also* introduce an arithmetic context and thus *also* cause bare words to be evaluated as number. (And even recursively get evaluated which combined makes for *incredibly* odd behavior for `[[ -eq`, etc. as far as I'm concerned.) – Etan Reisner Mar 10 '15 at 01:05
  • 1
    There are cases where the `$` is mandatory inside `((...))`: parameter expansion (obviously), to expand positional parameters `$1`, `$2`, etc. and when we specify the radix with `#` as in: `(( 10#$s == 0 ))`—something that should always be done! it's not enough to be sure that the variable consists of digits only; what I usually do, after `[[ $s =~ ^-?[[:digit:]]+$ ]]` (or similar) is to explicitly `((s=10#$s))`, and then I'm safe to work with `s`. – gniourf_gniourf Mar 10 '15 at 23:48
  • It's perhaps worth clarifying that "should always be done" in the above comment doesn't only refer to `(( ))`, and is also valid inside comparisons with `-eq` in other test constructs. – Charles Duffy Mar 10 '15 at 23:57