I am trying to make script that has two switches -h and -d, -d having a mandatory number argument. After it there will be undetermined number of paths to file. So far, I have this, but the code seems to not recognize invalid switch -r (can be any name) and also does not work when I do not input any switches:

while getopts ":hd:" opt; do
case $opt in
            echo $usage
        exit 0
        shift 2
            if [ "$OPTARG" -eq "$OPTARG" ] ; then # ako dalsi argument mame cislo
        shift 1
            shift 1
echo $1

when I type ./pripravne1.sh -d /home/OS/test_pz/test2 I get ./pripravne1.sh: [: /home/OS/test_pz/test2: integer expression expected when I type ./pripravne1.sh -r /home/OS/test_pz/test2 I get only empty string.


[ "$OPTARG" -eq "$OPTARG" ] ... is not the right way to check if $OPTARG is numeric -- it may print a nasty inscrutable error to the user if that's not the case, or it may just return true in all cases (in ksh), or also return true for an empty $OPTARG (in zsh).

Also, an option taking an argument may be given as either -d12 or -d 12, so a blind shift 2 won't cut it. And doing a shift inside the loop may badly interract with getopts, which is itself using the live argument list.

Taking that into account, this is what I propose:

die(){ echo >&2 "$@"; exit 1; }
usage(){ echo >&2 "usage: $0 [-h] [-d num] files..."; exit 0; }


while getopts :hd: opt; do
        case $opt in
        h)      usage ;;
        d)      case $OPTARG in
                ''|*[!-0-9]*|-|*?-*) die "invalid number $OPTARG" ;;
                *) depth=$OPTARG ;;
        :)      die "argument needed to -$OPTARG" ;;
        *)      die "invalid switch -$OPTARG" ;;
shift "$((OPTIND - 1))"

echo depth="$depth"
echo files="$@"
| improve this answer | |
  • 1
    [ being not a special it would not exit the shell. [ would return a non-zero exit status and output an error message if it didn't like an operand to -eq. POSIX says operands are to be decimal integer numbers but doesn't say what should happen if one passes operands that are not, and the behaviour varies between implementation. For instance, with OPTARG='x[$(reboot)]', in ksh, [ "$OPTARG" -eq "$OPTARG" ] would return true (assuming $x is unset or not things like nan, RANDOM, ++y...) and... reboot. – Stéphane Chazelas Oct 29 '18 at 18:44
  • 2
    Another thing not pointed out here (but corrected in the code) is that you should never use shift inside the while getopts loop. getopts takes care of stepping through the arguments itself, and if you change the arg list out from under it, things will get very confused. Instead, wait 'till after the loop, and then run shift "$((OPTIND - 1))" to remove all options from the arg list at once. – Gordon Davisson Oct 29 '18 at 18:49
  • @GordonDavisson, exactly. With the shift 2 in the code for -d, something like -d 1 -d 2 -d 3 would result in the code only seeing -d 1 and -d 3, the -d 2 being shifted away in between. – ilkkachu Oct 29 '18 at 21:21
  • fwiw, dash seems to be the only shell that handles well (ie the way I naively expect it) the arg list being changed from underneath getopts (either with shift or with set -- ...). – mosvy Oct 31 '18 at 21:15

The single square bracket [ is posix-compliant but harder to use than [[, which you can usually use in bash. Under the single-square-bracket standard, -eq is for integers only, not strings. For example, the following works fine: if [ "2" -eq "2" ] ; then echo foo; fi. You can either use double-square-brackets, for which -eq accepts strings, or use = and the single-square bracket form:

if [ "bar" = "bar" ] ; then echo foo; fi

Check out https://ryanstutorials.net/bash-scripting-tutorial/bash-if-statements.php for info on the POSIX if test and http://tldp.org/LDP/abs/html/testconstructs.html for info on different kinds of test constructs such as (( and [[.

| improve this answer | |
  • Thanks fór answer! :) But that does not solve shifting problem. Could you please add answer to that too ? – Traabefi Oct 22 '18 at 20:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.