1

I've been killing myself over this trying to figure it out, and I know it's probably super simple, so hoping a new pair of eyes can help. I have a Bourne shell (sh) script that I'm writing and it takes a list of integers as the input (and amount from 1 integer up, ideally I'd like to take both positive and negative ints). I'm trying to do an error check for the case if someone inputs something other than an integer. They could input "1 2 3 4 5 a" and it'd give an error, because the a is not an int.

I have an error check for no inputs that works, and I have code that does stuff to the list of integers themselves, but even when strings are given it still gets to my final code block.

I currently have a for loop to iterate through each item in the list of integers, then an if loop to give the error message if the argument in question isn't an int. I've tried a few different versions of this, but this is the most recent one so I've put it below.

for i in $@; do 
    if [ $i -ge 0 ] 2>/dev/null; then
        echo "Invalid input: integers only."
        exit 1
    fi 
done
MandyLB
  • 307
  • 1
  • 4
  • 18

3 Answers3

1

You could use a regex:

my_script.sh

for i in $@ ; do 
    if ! [[ "$i" =~ ^-?[0-9]+$ ]] ; then
        echo "Invalid input: integers only."
        exit 1
    fi
done

Example:

$ sh my_script.sh 1 2 3 4
$ sh my_script.sh 1 2 -12
$ sh my_script.sh 1 2 -12-2
Invalid input: integers only.
$ sh my_script.sh 1 2 a b
Invalid input: integers only.

Explanation of the regex:

  • ^: beginning of the string
  • -?: 0 or 1 times the character -
  • [0-9]+: 1 or more digit
  • $: end of the string
Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
1
#!/bin/sh
#

for i in "$@"
do 
    case "${i#[-+]}" in 
        0) 
            echo cannot be 0?
            exit 1
            ;; 
        *[!0-9]* | '')
            echo not int
            exit 2
            ;; 
    esac
done

echo i\'m ok

This should work, for both positive and negative ints. And if you admit that 0 is an integer, just delete the first case.

Almost duplicate: BASH: Test whether string is valid as an integer? And here is a good answer for posix. https://stackoverflow.com/a/18620446/7714132

alzee
  • 463
  • 2
  • 10
  • YES! This is the first one that's worked! Thank you! Also, would you mind explaining the logic because it so I fully understand how it's implemented? – MandyLB May 22 '18 at 01:25
  • It's pretty obvisous, you should dive in bash a little. Issue 'man bash' and search 'case', 'Pathname Expansion', 'Remove matching prefix pattern' and so on. – alzee May 22 '18 at 01:42
0

In POSIX sh, you can match your string against a glob with case:

#!/bin/sh
for i
do
  case "$i" in
    *[!0-9]*)
      echo "Integers only" >&2
      exit 1
  esac
done
echo "Ok"

Here's how it runs:

$ ./myscript 1 2 3 4 5
Ok

$ ./myscript 1 2 3 4 5 a
Integers only

The problem with your approach is primarily that you're checking for success rather than failure: [ will fail when the input is invalid.

that other guy
  • 116,971
  • 11
  • 170
  • 194
  • What is the purpose of the single round bracket in this? – MandyLB May 22 '18 at 00:20
  • @MandyLB Can you be more specific? For example, "I wrote a script `mytest` containing the line `./myscript 1 2 3` , but when I run `./mytest` I still get "Integers only" when I expected "Ok"" – that other guy May 22 '18 at 00:34
  • I have a full script, and like I said in my initial post, it works for checking for 0 inputs, and works for all integers, but the error check for non-integers doesn't work. The offered suggestions for how to fix the code (in my initial post) hasn't worked, and it still goes to the next code block and runs the inputs like integers, even when the check is supposed to stop that. Never gives an error saying the input isn't an int. – MandyLB May 22 '18 at 00:50
  • 1
    @MandyLB I don't understand. Do you get different results when you repeat my test cases? Or are you saying that the test cases worked fine, but you weren't able to apply it to a larger script? – that other guy May 22 '18 at 02:36