Search code examples
linuxshellgetopts

How to get program argument in a Linux shell script when also using getopts?


So I have a script where I want to process options with getopts but I also want to read arguments to the program itself in the usual way. So in this example script, I want to process the options and then echo the argument, given like ./script.sh -abc theargument. The problem that arises is that I don't know which shell argument is it. Argument isn't supposed to be related to the options, so you can call the script like ./script.sh theargument as well:

#!/bin/sh

while getopts "abc" opt; do
    case $opt in
        a) echo "option a" ;;
        b) echo "option b" ;;
        c) echo "option c" ;;
    esac
done

echo # what?

I can't just shift arguments with $OPTIND to make it $1 because options can be given like -abc, -a -b -c, -ab -c etc., so number of options doesn't correspond to the number of arguments.

Ideally I'd want to avoid bashisms


Solution

  • The bash way is to use indirection with ${!VARIABLE} - what VARIABLE expands to is treated as the parameter to use, so echo "${!OPTIND}" after the while loop in your example would display theargument.

    The more generic way is to use shift to discard the option arguments and then use $1 etc.:

    if [ "$OPTIND" -gt 1 ]; then
        shift $((OPTIND - 1))
    fi
    

    In your example $OPTIND is 2 after the loop, so this will shift the positional parameters left by 1, discarding the -abc and leaving theargument in $1. This approach works if you use -abc theargument, -ab -c theargument, -a -b -c theargument, and so on.