How to parse optional flags regardless of their position in script call and number of repetitions?

StackOverflow https://stackoverflow.com/questions/23290215

Question

I am writing a BASH script called stat which needs to parse its arguments in a way that it catches repetitions and different positions. The script can be called without any arguments, with an optional flag -r and optional filename also passed to the script as an argument, in this example directory1.

How can I parse the arguments so the following script calls are valid?

./stat
./stat -r
./stat directory1
./stat -r directory1
./stat directory1 -r
./stat directory1 -r -r
./stat -r directory1 -r

So far, I have a way to parse ./stat -r directory1.

recursive=0
while getopts ":r" opt; do
case $opt in
    r)
        recursive=1 
    ;;
    *)
                    echo "-$0: $opt is not a valid argument!"
        exit 1
    ;;
esac
done

This leaves me with parsing the directory name, which outputs only the directory name.

shift $((OPTIND-1)) #which removes processed options
echo "$*"

However, if I call the script with ./stat directory1 -r, ./stat -r directory1 -r or ./stat directory1 -r -r, the arguments are not properly parsed as the -r flag following the directory name is left out, not parsed and not removed with the shift $((OPTIND-1)) call.

So, I would like to know, how I can parse option flags so even redundant ones are captured along with the ones that may follow directory1.

Thank you for any help!

Was it helpful?

Solution

As you've found, getopts stops at the first non-option word. You're forced to iterate over all the arguments:

dir="some default"
recursive=false
for arg; do
    if [[ $arg == "-r" ]]; then
        recursive=true
    else
        dir=$arg
    fi
done

An advantage to using "true" and "false" like this is you can then write this, since true and false are programs on the $PATH:

if $recursive; then
    do_something_repeatedly
else
    do_something_once
fi

Checking for invalid options:

for arg; do
    case $arg in
        -r) recursive=true ;;
        -*) echo "invalid option: $arg" ;;
        *)  dir=$arg ;;
    esac
done
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top