1

I am trying to write a shell script with options that take different numbers of values in each run, e.g.

Run 1:

./myscript --input <file1> <file2> --output <folder1>

Run 2:

./myscript --input <file1> <file2> <file3> --output <folder1> <folder2>

I tried using getopts as follows:

while getopts ":i:o:" opt; do
  case $opt in
  i)
    echo "treatment files are: $OPTARG" >&2
    infiles="${OPTARG}"
  ;;
  o)
    echo "control files are: $OPTARG" >&2
    outdir="${OPTARG}"
  ;;
  \?)
    echo "Invalid option: -$OPTARG" >&2
    exit 1
  ;;
  :)
    echo "Option -$OPTARG requires an argument." >&2
    exit 1
  ;;
  esac
done

However, the only way I found to input variable amounts of values for the "-i" option is by quotation ("file1 file2"), which prevents me/the user to use the autocomplete function of the command line to help generating the file path. Also this option does not seem allow me to use "--input" syntax to pass the options.

Anybody can help?

Thanks a lot.

gdeniz
  • 169
  • 9
  • See [*KoZm0kNoT*'s answer to *Retrieving multiple arguments for a single option using getopts in Bash*](https://stackoverflow.com/a/42840610/6136214) – agc May 25 '18 at 04:04
  • Possible duplicate of [Retrieving multiple arguments for a single option using getopts in Bash](https://stackoverflow.com/questions/7529856/retrieving-multiple-arguments-for-a-single-option-using-getopts-in-bash) – agc May 25 '18 at 04:06

1 Answers1

3

You have two questions here. One of them is "how do I implement long options in my shell script?", for which there is good reading here.

The other question is, "how do I make an option accept an arbitrary number of arguments?" The answer there is, mostly, "you don't". Often the cleanest solution is to have your script accept the option multiple times, as in:

./myscript -i <file1> -i <file2> -i <file3>

This is relatively easy to handle by appending to a Bash array, as in:

infiles=()
while getopts ":i:o:" opt; do
  case $opt in
  i)
    infiles+=("${OPTARG}")
  ;;
  esac
done

And later on you can iterate over those values:

for inputfile in "${infiles[@]}"; do
  ...
done

Read about bash arrays for more information.

If you don't like that solution, you could implement your own option parsing in a manner similar to some of the answers to the question to which I linked in the first paragraph. That would allow you to get the command line semantics you want, although I would argue that behavior is at odds with the way a typical program behaves.

larsks
  • 277,717
  • 41
  • 399
  • 399