Matching numbers with regex in case statementWhy does my regular expression work in X but not in Y?Number of...

What do the "optional" resistor and capacitor do in this circuit?

Can anyone give me examples of the relative-determinative 'which'?

tikz drawing rectangle discretized with triangle lattices and its centroids

It is as easy as A B C, Figure out U V C from the given relationship

Why would someone open a Netflix account using my Gmail address?

History of the Frobenius Endomorphism?

With today's technology, could iron be smelted at La Rinconada?

Understanding Python syntax in lists vs series

Could a space colony 1g from the sun work?

Break long word (not long text!) in longtable cell

Did any "washouts" of the Mercury program eventually become astronauts?

Will consteval functions allow template parameters dependent on function arguments?

How does a permutation act on a string?

How to not get blinded by an attack at dawn

Why doesn't Iron Man's action affect this person in Endgame?

Why do OOK transmissions have bandwidth?

Does the Rogue's Reliable Talent feature work for thieves' tools, since the rogue is proficient in them?

When did game consoles begin including FPUs?

Formal Definition of Dot Product

Do high-wing aircraft represent more difficult engineering challenges than low-wing aircraft?

How to check if comma list is empty?

​Cuban​ ​Primes

Does it matter what way the tires go if no directional arrow?

Does this "yield your space to an ally" rule my 3.5 group uses appear anywhere in the official rules?



Matching numbers with regex in case statement


Why does my regular expression work in X but not in Y?Number of backslashes needed for escaping regex backslash on the command-lineRegex for phrase matching with case statement in kshregex matching with “locate”Is there a special variable containing a case statement matchRegex in case statementbash script with case statement not returning an outputPass argument to function with case statementCase statement allow only alphabetic characters?Match wildcarded string in case statement using sh shellbash script with case statement conditions not getting executed






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







1















How to write a case statement using regex as condition (to match numbers)? I try few deferent ways I come up with (e.g. [0-9]+ or ^[0-9][0-9]*$), non of them works. Like in following example the statement is matching the wildcard but not the numeric regex.



i=1
let arg_n=$#+1

while (( $i < $arg_n )); do
case ${!i} in
[0-9]+)
n=${!i}
;;
*)
echo 'Invalid argument!'
;;
esac
let i=$i+1
done


Output:



$ ./cmd.sh 64
Invalid argument!









share|improve this question

























  • This variable indirection works just fine. I have more cases in the real script and it works. I'm trying to match any occurrence of real numbers in the program arguments. So 0 or 999 should match. Else if there is some invalid argument like '-x' or letters in stead of numbers, program shall match *, at least thats what I thought.

    – siery
    Mar 21 '18 at 19:35













  • @John1024, numbers aren't valid names for variables, but they're quite valid for the names of the positional parameters, and ${!i} works fine for those. e.g. set -- aa bb cc; i=2; echo ${!i} prints bb

    – ilkkachu
    Mar 21 '18 at 22:45











  • that said, the easier way to loop over the arguments to the script would be to just use for val in "$@"; do ... and use $val in the loop

    – ilkkachu
    Mar 21 '18 at 22:46













  • Read unix.stackexchange.com/questions/119905/…

    – Gilles
    Mar 21 '18 at 22:56











  • @John1024, and when it's run, i contains 1, so ${!i} is the same as $1: it expands to the value of the first argument, be it 64 or abc or whatever. What they have is just a convoluted way of looping over the positional parameters / command line arguments.

    – ilkkachu
    Mar 21 '18 at 23:14


















1















How to write a case statement using regex as condition (to match numbers)? I try few deferent ways I come up with (e.g. [0-9]+ or ^[0-9][0-9]*$), non of them works. Like in following example the statement is matching the wildcard but not the numeric regex.



i=1
let arg_n=$#+1

while (( $i < $arg_n )); do
case ${!i} in
[0-9]+)
n=${!i}
;;
*)
echo 'Invalid argument!'
;;
esac
let i=$i+1
done


Output:



$ ./cmd.sh 64
Invalid argument!









share|improve this question

























  • This variable indirection works just fine. I have more cases in the real script and it works. I'm trying to match any occurrence of real numbers in the program arguments. So 0 or 999 should match. Else if there is some invalid argument like '-x' or letters in stead of numbers, program shall match *, at least thats what I thought.

    – siery
    Mar 21 '18 at 19:35













  • @John1024, numbers aren't valid names for variables, but they're quite valid for the names of the positional parameters, and ${!i} works fine for those. e.g. set -- aa bb cc; i=2; echo ${!i} prints bb

    – ilkkachu
    Mar 21 '18 at 22:45











  • that said, the easier way to loop over the arguments to the script would be to just use for val in "$@"; do ... and use $val in the loop

    – ilkkachu
    Mar 21 '18 at 22:46













  • Read unix.stackexchange.com/questions/119905/…

    – Gilles
    Mar 21 '18 at 22:56











  • @John1024, and when it's run, i contains 1, so ${!i} is the same as $1: it expands to the value of the first argument, be it 64 or abc or whatever. What they have is just a convoluted way of looping over the positional parameters / command line arguments.

    – ilkkachu
    Mar 21 '18 at 23:14














1












1








1








How to write a case statement using regex as condition (to match numbers)? I try few deferent ways I come up with (e.g. [0-9]+ or ^[0-9][0-9]*$), non of them works. Like in following example the statement is matching the wildcard but not the numeric regex.



i=1
let arg_n=$#+1

while (( $i < $arg_n )); do
case ${!i} in
[0-9]+)
n=${!i}
;;
*)
echo 'Invalid argument!'
;;
esac
let i=$i+1
done


Output:



$ ./cmd.sh 64
Invalid argument!









share|improve this question
















How to write a case statement using regex as condition (to match numbers)? I try few deferent ways I come up with (e.g. [0-9]+ or ^[0-9][0-9]*$), non of them works. Like in following example the statement is matching the wildcard but not the numeric regex.



i=1
let arg_n=$#+1

while (( $i < $arg_n )); do
case ${!i} in
[0-9]+)
n=${!i}
;;
*)
echo 'Invalid argument!'
;;
esac
let i=$i+1
done


Output:



$ ./cmd.sh 64
Invalid argument!






bash regular-expression case






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 45 mins ago







siery

















asked Mar 21 '18 at 19:21









sierysiery

3418




3418













  • This variable indirection works just fine. I have more cases in the real script and it works. I'm trying to match any occurrence of real numbers in the program arguments. So 0 or 999 should match. Else if there is some invalid argument like '-x' or letters in stead of numbers, program shall match *, at least thats what I thought.

    – siery
    Mar 21 '18 at 19:35













  • @John1024, numbers aren't valid names for variables, but they're quite valid for the names of the positional parameters, and ${!i} works fine for those. e.g. set -- aa bb cc; i=2; echo ${!i} prints bb

    – ilkkachu
    Mar 21 '18 at 22:45











  • that said, the easier way to loop over the arguments to the script would be to just use for val in "$@"; do ... and use $val in the loop

    – ilkkachu
    Mar 21 '18 at 22:46













  • Read unix.stackexchange.com/questions/119905/…

    – Gilles
    Mar 21 '18 at 22:56











  • @John1024, and when it's run, i contains 1, so ${!i} is the same as $1: it expands to the value of the first argument, be it 64 or abc or whatever. What they have is just a convoluted way of looping over the positional parameters / command line arguments.

    – ilkkachu
    Mar 21 '18 at 23:14



















  • This variable indirection works just fine. I have more cases in the real script and it works. I'm trying to match any occurrence of real numbers in the program arguments. So 0 or 999 should match. Else if there is some invalid argument like '-x' or letters in stead of numbers, program shall match *, at least thats what I thought.

    – siery
    Mar 21 '18 at 19:35













  • @John1024, numbers aren't valid names for variables, but they're quite valid for the names of the positional parameters, and ${!i} works fine for those. e.g. set -- aa bb cc; i=2; echo ${!i} prints bb

    – ilkkachu
    Mar 21 '18 at 22:45











  • that said, the easier way to loop over the arguments to the script would be to just use for val in "$@"; do ... and use $val in the loop

    – ilkkachu
    Mar 21 '18 at 22:46













  • Read unix.stackexchange.com/questions/119905/…

    – Gilles
    Mar 21 '18 at 22:56











  • @John1024, and when it's run, i contains 1, so ${!i} is the same as $1: it expands to the value of the first argument, be it 64 or abc or whatever. What they have is just a convoluted way of looping over the positional parameters / command line arguments.

    – ilkkachu
    Mar 21 '18 at 23:14

















This variable indirection works just fine. I have more cases in the real script and it works. I'm trying to match any occurrence of real numbers in the program arguments. So 0 or 999 should match. Else if there is some invalid argument like '-x' or letters in stead of numbers, program shall match *, at least thats what I thought.

– siery
Mar 21 '18 at 19:35







This variable indirection works just fine. I have more cases in the real script and it works. I'm trying to match any occurrence of real numbers in the program arguments. So 0 or 999 should match. Else if there is some invalid argument like '-x' or letters in stead of numbers, program shall match *, at least thats what I thought.

– siery
Mar 21 '18 at 19:35















@John1024, numbers aren't valid names for variables, but they're quite valid for the names of the positional parameters, and ${!i} works fine for those. e.g. set -- aa bb cc; i=2; echo ${!i} prints bb

– ilkkachu
Mar 21 '18 at 22:45





@John1024, numbers aren't valid names for variables, but they're quite valid for the names of the positional parameters, and ${!i} works fine for those. e.g. set -- aa bb cc; i=2; echo ${!i} prints bb

– ilkkachu
Mar 21 '18 at 22:45













that said, the easier way to loop over the arguments to the script would be to just use for val in "$@"; do ... and use $val in the loop

– ilkkachu
Mar 21 '18 at 22:46







that said, the easier way to loop over the arguments to the script would be to just use for val in "$@"; do ... and use $val in the loop

– ilkkachu
Mar 21 '18 at 22:46















Read unix.stackexchange.com/questions/119905/…

– Gilles
Mar 21 '18 at 22:56





Read unix.stackexchange.com/questions/119905/…

– Gilles
Mar 21 '18 at 22:56













@John1024, and when it's run, i contains 1, so ${!i} is the same as $1: it expands to the value of the first argument, be it 64 or abc or whatever. What they have is just a convoluted way of looping over the positional parameters / command line arguments.

– ilkkachu
Mar 21 '18 at 23:14





@John1024, and when it's run, i contains 1, so ${!i} is the same as $1: it expands to the value of the first argument, be it 64 or abc or whatever. What they have is just a convoluted way of looping over the positional parameters / command line arguments.

– ilkkachu
Mar 21 '18 at 23:14










3 Answers
3






active

oldest

votes


















9














case does not use regexes, it uses patterns



For "1 or more digits", do this:



shopt -s extglob
...
case ${!i} in
+([[:digit:]]) )
n=${!i}
;;
...


If you want to use regular expressions, use the =~ operator within [[...]]



if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
n=${!i}
else
echo "Invalid"
fi





share|improve this answer































    2














    As glenn says, “case does not use regexes, it uses patterns”. 
    As bash(1) says,




    case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac



          A case command first expands word,
          and tries to match it against each pattern in turn,
          using the same matching rules as for pathname expansion
          (see Pathname Expansion below).



    Similarly, the POSIX specification says,




    … each pattern … shall be compared against the expansion of word,
    according to the rules described in Pattern Matching Notation …




    So the patterns are pathname expansion patterns,
    a.k.a. wildcards, a.k.a. globs, as in ls -l -- *.sh or rm -- *.bak.



    Sure, shopt -s extglob and [[ … =~ … ]]
    are the neatest thing since sliced bread,
    but they aren’t POSIX,
    and it can be useful to know how to use the original tools. 
    For years, programmers checked, for example,
    whether a string was a number
    by checking whether it was not not a number. 
    You’ve defined a number to be a string that consists
    (entirely) of one or more digits. 
    So a string is not a number if it is null,
    or if it contains a character that is not a digit. 
    We can test these conditions with a case statement as follows:



    case "$1" in
    ("")
    # null

    ;;
    (*[!0-9]*)
    # contains non-numeric character(s)

    ;;
    (*)
    # is a whole number (non-negative integer)

    esac


    where [!0-9] is the old-timey shell way of saying [^0-9],
    which, of course, means any character other than a digit. 
    ([!…] and [^…] both work in bash. 
    [!…] is required to work by POSIX; the result of [^…] is unspecified.) 
    If you don’t care which kind of non-number a string is,
    you can combine the non-number patterns:



    case "$1" in
    ("" | *[!0-9]*)
    # not a number

    ;;
    (*)
    # is a number

    esac


    As an exercise,
    here’s a case statement to handle any kind of real number —
    to be precise, a string of one or more digits,
    with optionally a period (.) somewhere,
    and optionally a minus sign (-) at the beginning.



    case "$1" in
    (*[!-.0-9]*)
    # contains non-numeric character(s)
    ;;
    (*?-*)
    # contains '-' somewhere other than the first position
    ;;
    (*.*.*)
    # contains multiple decimal points
    ;;
    (*)
    case "$1" in
    (*[0-9]*)
    # is a real number
    ;;
    (*)
    # not a number
    esac
    esac


    I added the case-within-a-case to verify that the string does, indeed,
    contain at least one digit. 
    That wasn’t necessary in the integer example
    because I tested whether the string was null;
    a test which I have removed from this statement. 
    Without the second case, a single - or a single .
    or even -. — would qualify as a number. 
    Of course we could add patterns to handle those exceptions,
    but that can get complex. 
    (For example, I almost posted this answer
    without realizing that -. was one of the exceptions.) 
    I believe that the above approach is more flexible and robust.



    Of course the non-number patterns can be combined here, too:
    (*[!-.0-9]* | *?-* | *.*.*).






    share|improve this answer


























    • Note that on many systems and locales [0-9] matches more than [0123456789]. Generally, you can't rely on ranges outside of the C locale. [[:digit:]] should be OK though. [0123456789] is the safest.

      – Stéphane Chazelas
      13 mins ago



















    1














    To match numbers with regexp in case statements, you'd need a shell whose wildcards support regexps. I only know of ksh93 with those.



    With ksh93 globs, you can do ~(E)^[0-9]+$ or ~(E:^[0-9]+$) to use an Extended regexp in a glob pattern, or ~(P)^d+$ to use a perl-like regexp (also G for basic regexp, X for augmented regexp, V for SysV regexp).



    So:



    #! /bin/ksh93
    for i do
    case $i in
    (~(E)^[0-9]+$)
    n=$i;;
    (*)
    echo >&2 'Invalid argument!'
    usage
    esac
    done





    share|improve this answer
























      Your Answer








      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "106"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f432660%2fmatching-numbers-with-regex-in-case-statement%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      9














      case does not use regexes, it uses patterns



      For "1 or more digits", do this:



      shopt -s extglob
      ...
      case ${!i} in
      +([[:digit:]]) )
      n=${!i}
      ;;
      ...


      If you want to use regular expressions, use the =~ operator within [[...]]



      if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
      n=${!i}
      else
      echo "Invalid"
      fi





      share|improve this answer




























        9














        case does not use regexes, it uses patterns



        For "1 or more digits", do this:



        shopt -s extglob
        ...
        case ${!i} in
        +([[:digit:]]) )
        n=${!i}
        ;;
        ...


        If you want to use regular expressions, use the =~ operator within [[...]]



        if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
        n=${!i}
        else
        echo "Invalid"
        fi





        share|improve this answer


























          9












          9








          9







          case does not use regexes, it uses patterns



          For "1 or more digits", do this:



          shopt -s extglob
          ...
          case ${!i} in
          +([[:digit:]]) )
          n=${!i}
          ;;
          ...


          If you want to use regular expressions, use the =~ operator within [[...]]



          if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
          n=${!i}
          else
          echo "Invalid"
          fi





          share|improve this answer













          case does not use regexes, it uses patterns



          For "1 or more digits", do this:



          shopt -s extglob
          ...
          case ${!i} in
          +([[:digit:]]) )
          n=${!i}
          ;;
          ...


          If you want to use regular expressions, use the =~ operator within [[...]]



          if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
          n=${!i}
          else
          echo "Invalid"
          fi






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 21 '18 at 19:41









          glenn jackmanglenn jackman

          53.7k673115




          53.7k673115

























              2














              As glenn says, “case does not use regexes, it uses patterns”. 
              As bash(1) says,




              case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac



                    A case command first expands word,
                    and tries to match it against each pattern in turn,
                    using the same matching rules as for pathname expansion
                    (see Pathname Expansion below).



              Similarly, the POSIX specification says,




              … each pattern … shall be compared against the expansion of word,
              according to the rules described in Pattern Matching Notation …




              So the patterns are pathname expansion patterns,
              a.k.a. wildcards, a.k.a. globs, as in ls -l -- *.sh or rm -- *.bak.



              Sure, shopt -s extglob and [[ … =~ … ]]
              are the neatest thing since sliced bread,
              but they aren’t POSIX,
              and it can be useful to know how to use the original tools. 
              For years, programmers checked, for example,
              whether a string was a number
              by checking whether it was not not a number. 
              You’ve defined a number to be a string that consists
              (entirely) of one or more digits. 
              So a string is not a number if it is null,
              or if it contains a character that is not a digit. 
              We can test these conditions with a case statement as follows:



              case "$1" in
              ("")
              # null

              ;;
              (*[!0-9]*)
              # contains non-numeric character(s)

              ;;
              (*)
              # is a whole number (non-negative integer)

              esac


              where [!0-9] is the old-timey shell way of saying [^0-9],
              which, of course, means any character other than a digit. 
              ([!…] and [^…] both work in bash. 
              [!…] is required to work by POSIX; the result of [^…] is unspecified.) 
              If you don’t care which kind of non-number a string is,
              you can combine the non-number patterns:



              case "$1" in
              ("" | *[!0-9]*)
              # not a number

              ;;
              (*)
              # is a number

              esac


              As an exercise,
              here’s a case statement to handle any kind of real number —
              to be precise, a string of one or more digits,
              with optionally a period (.) somewhere,
              and optionally a minus sign (-) at the beginning.



              case "$1" in
              (*[!-.0-9]*)
              # contains non-numeric character(s)
              ;;
              (*?-*)
              # contains '-' somewhere other than the first position
              ;;
              (*.*.*)
              # contains multiple decimal points
              ;;
              (*)
              case "$1" in
              (*[0-9]*)
              # is a real number
              ;;
              (*)
              # not a number
              esac
              esac


              I added the case-within-a-case to verify that the string does, indeed,
              contain at least one digit. 
              That wasn’t necessary in the integer example
              because I tested whether the string was null;
              a test which I have removed from this statement. 
              Without the second case, a single - or a single .
              or even -. — would qualify as a number. 
              Of course we could add patterns to handle those exceptions,
              but that can get complex. 
              (For example, I almost posted this answer
              without realizing that -. was one of the exceptions.) 
              I believe that the above approach is more flexible and robust.



              Of course the non-number patterns can be combined here, too:
              (*[!-.0-9]* | *?-* | *.*.*).






              share|improve this answer


























              • Note that on many systems and locales [0-9] matches more than [0123456789]. Generally, you can't rely on ranges outside of the C locale. [[:digit:]] should be OK though. [0123456789] is the safest.

                – Stéphane Chazelas
                13 mins ago
















              2














              As glenn says, “case does not use regexes, it uses patterns”. 
              As bash(1) says,




              case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac



                    A case command first expands word,
                    and tries to match it against each pattern in turn,
                    using the same matching rules as for pathname expansion
                    (see Pathname Expansion below).



              Similarly, the POSIX specification says,




              … each pattern … shall be compared against the expansion of word,
              according to the rules described in Pattern Matching Notation …




              So the patterns are pathname expansion patterns,
              a.k.a. wildcards, a.k.a. globs, as in ls -l -- *.sh or rm -- *.bak.



              Sure, shopt -s extglob and [[ … =~ … ]]
              are the neatest thing since sliced bread,
              but they aren’t POSIX,
              and it can be useful to know how to use the original tools. 
              For years, programmers checked, for example,
              whether a string was a number
              by checking whether it was not not a number. 
              You’ve defined a number to be a string that consists
              (entirely) of one or more digits. 
              So a string is not a number if it is null,
              or if it contains a character that is not a digit. 
              We can test these conditions with a case statement as follows:



              case "$1" in
              ("")
              # null

              ;;
              (*[!0-9]*)
              # contains non-numeric character(s)

              ;;
              (*)
              # is a whole number (non-negative integer)

              esac


              where [!0-9] is the old-timey shell way of saying [^0-9],
              which, of course, means any character other than a digit. 
              ([!…] and [^…] both work in bash. 
              [!…] is required to work by POSIX; the result of [^…] is unspecified.) 
              If you don’t care which kind of non-number a string is,
              you can combine the non-number patterns:



              case "$1" in
              ("" | *[!0-9]*)
              # not a number

              ;;
              (*)
              # is a number

              esac


              As an exercise,
              here’s a case statement to handle any kind of real number —
              to be precise, a string of one or more digits,
              with optionally a period (.) somewhere,
              and optionally a minus sign (-) at the beginning.



              case "$1" in
              (*[!-.0-9]*)
              # contains non-numeric character(s)
              ;;
              (*?-*)
              # contains '-' somewhere other than the first position
              ;;
              (*.*.*)
              # contains multiple decimal points
              ;;
              (*)
              case "$1" in
              (*[0-9]*)
              # is a real number
              ;;
              (*)
              # not a number
              esac
              esac


              I added the case-within-a-case to verify that the string does, indeed,
              contain at least one digit. 
              That wasn’t necessary in the integer example
              because I tested whether the string was null;
              a test which I have removed from this statement. 
              Without the second case, a single - or a single .
              or even -. — would qualify as a number. 
              Of course we could add patterns to handle those exceptions,
              but that can get complex. 
              (For example, I almost posted this answer
              without realizing that -. was one of the exceptions.) 
              I believe that the above approach is more flexible and robust.



              Of course the non-number patterns can be combined here, too:
              (*[!-.0-9]* | *?-* | *.*.*).






              share|improve this answer


























              • Note that on many systems and locales [0-9] matches more than [0123456789]. Generally, you can't rely on ranges outside of the C locale. [[:digit:]] should be OK though. [0123456789] is the safest.

                – Stéphane Chazelas
                13 mins ago














              2












              2








              2







              As glenn says, “case does not use regexes, it uses patterns”. 
              As bash(1) says,




              case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac



                    A case command first expands word,
                    and tries to match it against each pattern in turn,
                    using the same matching rules as for pathname expansion
                    (see Pathname Expansion below).



              Similarly, the POSIX specification says,




              … each pattern … shall be compared against the expansion of word,
              according to the rules described in Pattern Matching Notation …




              So the patterns are pathname expansion patterns,
              a.k.a. wildcards, a.k.a. globs, as in ls -l -- *.sh or rm -- *.bak.



              Sure, shopt -s extglob and [[ … =~ … ]]
              are the neatest thing since sliced bread,
              but they aren’t POSIX,
              and it can be useful to know how to use the original tools. 
              For years, programmers checked, for example,
              whether a string was a number
              by checking whether it was not not a number. 
              You’ve defined a number to be a string that consists
              (entirely) of one or more digits. 
              So a string is not a number if it is null,
              or if it contains a character that is not a digit. 
              We can test these conditions with a case statement as follows:



              case "$1" in
              ("")
              # null

              ;;
              (*[!0-9]*)
              # contains non-numeric character(s)

              ;;
              (*)
              # is a whole number (non-negative integer)

              esac


              where [!0-9] is the old-timey shell way of saying [^0-9],
              which, of course, means any character other than a digit. 
              ([!…] and [^…] both work in bash. 
              [!…] is required to work by POSIX; the result of [^…] is unspecified.) 
              If you don’t care which kind of non-number a string is,
              you can combine the non-number patterns:



              case "$1" in
              ("" | *[!0-9]*)
              # not a number

              ;;
              (*)
              # is a number

              esac


              As an exercise,
              here’s a case statement to handle any kind of real number —
              to be precise, a string of one or more digits,
              with optionally a period (.) somewhere,
              and optionally a minus sign (-) at the beginning.



              case "$1" in
              (*[!-.0-9]*)
              # contains non-numeric character(s)
              ;;
              (*?-*)
              # contains '-' somewhere other than the first position
              ;;
              (*.*.*)
              # contains multiple decimal points
              ;;
              (*)
              case "$1" in
              (*[0-9]*)
              # is a real number
              ;;
              (*)
              # not a number
              esac
              esac


              I added the case-within-a-case to verify that the string does, indeed,
              contain at least one digit. 
              That wasn’t necessary in the integer example
              because I tested whether the string was null;
              a test which I have removed from this statement. 
              Without the second case, a single - or a single .
              or even -. — would qualify as a number. 
              Of course we could add patterns to handle those exceptions,
              but that can get complex. 
              (For example, I almost posted this answer
              without realizing that -. was one of the exceptions.) 
              I believe that the above approach is more flexible and robust.



              Of course the non-number patterns can be combined here, too:
              (*[!-.0-9]* | *?-* | *.*.*).






              share|improve this answer















              As glenn says, “case does not use regexes, it uses patterns”. 
              As bash(1) says,




              case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac



                    A case command first expands word,
                    and tries to match it against each pattern in turn,
                    using the same matching rules as for pathname expansion
                    (see Pathname Expansion below).



              Similarly, the POSIX specification says,




              … each pattern … shall be compared against the expansion of word,
              according to the rules described in Pattern Matching Notation …




              So the patterns are pathname expansion patterns,
              a.k.a. wildcards, a.k.a. globs, as in ls -l -- *.sh or rm -- *.bak.



              Sure, shopt -s extglob and [[ … =~ … ]]
              are the neatest thing since sliced bread,
              but they aren’t POSIX,
              and it can be useful to know how to use the original tools. 
              For years, programmers checked, for example,
              whether a string was a number
              by checking whether it was not not a number. 
              You’ve defined a number to be a string that consists
              (entirely) of one or more digits. 
              So a string is not a number if it is null,
              or if it contains a character that is not a digit. 
              We can test these conditions with a case statement as follows:



              case "$1" in
              ("")
              # null

              ;;
              (*[!0-9]*)
              # contains non-numeric character(s)

              ;;
              (*)
              # is a whole number (non-negative integer)

              esac


              where [!0-9] is the old-timey shell way of saying [^0-9],
              which, of course, means any character other than a digit. 
              ([!…] and [^…] both work in bash. 
              [!…] is required to work by POSIX; the result of [^…] is unspecified.) 
              If you don’t care which kind of non-number a string is,
              you can combine the non-number patterns:



              case "$1" in
              ("" | *[!0-9]*)
              # not a number

              ;;
              (*)
              # is a number

              esac


              As an exercise,
              here’s a case statement to handle any kind of real number —
              to be precise, a string of one or more digits,
              with optionally a period (.) somewhere,
              and optionally a minus sign (-) at the beginning.



              case "$1" in
              (*[!-.0-9]*)
              # contains non-numeric character(s)
              ;;
              (*?-*)
              # contains '-' somewhere other than the first position
              ;;
              (*.*.*)
              # contains multiple decimal points
              ;;
              (*)
              case "$1" in
              (*[0-9]*)
              # is a real number
              ;;
              (*)
              # not a number
              esac
              esac


              I added the case-within-a-case to verify that the string does, indeed,
              contain at least one digit. 
              That wasn’t necessary in the integer example
              because I tested whether the string was null;
              a test which I have removed from this statement. 
              Without the second case, a single - or a single .
              or even -. — would qualify as a number. 
              Of course we could add patterns to handle those exceptions,
              but that can get complex. 
              (For example, I almost posted this answer
              without realizing that -. was one of the exceptions.) 
              I believe that the above approach is more flexible and robust.



              Of course the non-number patterns can be combined here, too:
              (*[!-.0-9]* | *?-* | *.*.*).







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Mar 22 '18 at 18:26

























              answered Mar 22 '18 at 5:09









              G-ManG-Man

              14.2k93973




              14.2k93973













              • Note that on many systems and locales [0-9] matches more than [0123456789]. Generally, you can't rely on ranges outside of the C locale. [[:digit:]] should be OK though. [0123456789] is the safest.

                – Stéphane Chazelas
                13 mins ago



















              • Note that on many systems and locales [0-9] matches more than [0123456789]. Generally, you can't rely on ranges outside of the C locale. [[:digit:]] should be OK though. [0123456789] is the safest.

                – Stéphane Chazelas
                13 mins ago

















              Note that on many systems and locales [0-9] matches more than [0123456789]. Generally, you can't rely on ranges outside of the C locale. [[:digit:]] should be OK though. [0123456789] is the safest.

              – Stéphane Chazelas
              13 mins ago





              Note that on many systems and locales [0-9] matches more than [0123456789]. Generally, you can't rely on ranges outside of the C locale. [[:digit:]] should be OK though. [0123456789] is the safest.

              – Stéphane Chazelas
              13 mins ago











              1














              To match numbers with regexp in case statements, you'd need a shell whose wildcards support regexps. I only know of ksh93 with those.



              With ksh93 globs, you can do ~(E)^[0-9]+$ or ~(E:^[0-9]+$) to use an Extended regexp in a glob pattern, or ~(P)^d+$ to use a perl-like regexp (also G for basic regexp, X for augmented regexp, V for SysV regexp).



              So:



              #! /bin/ksh93
              for i do
              case $i in
              (~(E)^[0-9]+$)
              n=$i;;
              (*)
              echo >&2 'Invalid argument!'
              usage
              esac
              done





              share|improve this answer




























                1














                To match numbers with regexp in case statements, you'd need a shell whose wildcards support regexps. I only know of ksh93 with those.



                With ksh93 globs, you can do ~(E)^[0-9]+$ or ~(E:^[0-9]+$) to use an Extended regexp in a glob pattern, or ~(P)^d+$ to use a perl-like regexp (also G for basic regexp, X for augmented regexp, V for SysV regexp).



                So:



                #! /bin/ksh93
                for i do
                case $i in
                (~(E)^[0-9]+$)
                n=$i;;
                (*)
                echo >&2 'Invalid argument!'
                usage
                esac
                done





                share|improve this answer


























                  1












                  1








                  1







                  To match numbers with regexp in case statements, you'd need a shell whose wildcards support regexps. I only know of ksh93 with those.



                  With ksh93 globs, you can do ~(E)^[0-9]+$ or ~(E:^[0-9]+$) to use an Extended regexp in a glob pattern, or ~(P)^d+$ to use a perl-like regexp (also G for basic regexp, X for augmented regexp, V for SysV regexp).



                  So:



                  #! /bin/ksh93
                  for i do
                  case $i in
                  (~(E)^[0-9]+$)
                  n=$i;;
                  (*)
                  echo >&2 'Invalid argument!'
                  usage
                  esac
                  done





                  share|improve this answer













                  To match numbers with regexp in case statements, you'd need a shell whose wildcards support regexps. I only know of ksh93 with those.



                  With ksh93 globs, you can do ~(E)^[0-9]+$ or ~(E:^[0-9]+$) to use an Extended regexp in a glob pattern, or ~(P)^d+$ to use a perl-like regexp (also G for basic regexp, X for augmented regexp, V for SysV regexp).



                  So:



                  #! /bin/ksh93
                  for i do
                  case $i in
                  (~(E)^[0-9]+$)
                  n=$i;;
                  (*)
                  echo >&2 'Invalid argument!'
                  usage
                  esac
                  done






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Mar 22 '18 at 7:30









                  Stéphane ChazelasStéphane Chazelas

                  318k57602966




                  318k57602966






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Unix & Linux Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f432660%2fmatching-numbers-with-regex-in-case-statement%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Taj Mahal Inhaltsverzeichnis Aufbau | Geschichte | 350-Jahr-Feier | Heutige Bedeutung | Siehe auch |...

                      Baia Sprie Cuprins Etimologie | Istorie | Demografie | Politică și administrație | Arii naturale...

                      Nicolae Petrescu-Găină Cuprins Biografie | Opera | In memoriam | Varia | Controverse, incertitudini...