Search code examples
bashshellunixgetopts

A shell script "getopts error"


I have this code:

#!/bin/bash
if [ $# -lt 2 ]; then
    echo "usage: $0 <-lu> <string>"
    exit 1
fi
while getopts "lu" OPT
do
    case $OPT in
        u) casechange=0;;
        l) casechange=1;;
        *) echo "usage: -u<upper> || -l<lower> <string>";
            exit 1;;
    esac
done
shift $(( $optind -1 ))
if [ $casechange -eq 0 ]; then
    tr '[A-Z]' '[a-z]' <$string
elif [ $casechange -eq 1 ]; then
    tr '[a-z]' '[A-Z]' <$string
else
    echo "fatal error"
    exit 1
fi

I get two errors:

  • line 15: shift -1: shift count out of range
  • line 19: $string: ambiguous redirect

What am I doing wrong? How do I fix this?


Solution

  • OPTIND needs to be in uppercase letters. Bash is case sensitive by default. That makes $optind empty and you're effectively trying to shift by -1.

    Also, after processing the options, you need to do something with nonoption arguments: string="$1"

    and then tr '[A-Z]' '[a-z]' <<<"$string" for your redirects from a variable. Lastly, your sad path outputs should be to stderr (>&2).

    All combined (+some minor improvements):

    #!/bin/bash
    if [[ $# -lt 2 ]]; then
        echo "usage: $0 <-lu> <string>" >&2
        exit 1
    fi
    while getopts "lu" OPT
    do
        case $OPT in
            u) casechange=0;;
            l) casechange=1;;
            *) echo "usage: -u<upper> || -l<lower> <string>" >&2;
                exit 1;;
        esac
    done
    shift $(( $OPTIND -1 ))
    string="$1"
    if [[ "$casechange" -eq 0 ]]; then
        tr 'A-Z' 'a-z' <<<"$string"
    elif [[ "$casechange" -eq 1 ]]; then
        tr 'a-z' 'A-Z' <<<"$string"
    else
        echo "fatal error" >&2
        exit 1
    fi