Retrieving multiple arguments for a single option using getopts in Bash Retrieving multiple arguments for a single option using getopts in Bash bash bash

Retrieving multiple arguments for a single option using getopts in Bash


You can use the same option multiple times and add all values to an array.

For the very specific original question here, Ryan's mkdir -p solution is obviously the best.

However, for the more general question of getting multiple values from the same option with getopts, here it is:

#!/bin/bashwhile getopts "m:" opt; do    case $opt in        m) multi+=("$OPTARG");;        #...    esacdoneshift $((OPTIND -1))echo "The first value of the array 'multi' is '$multi'"echo "The whole list of values is '${multi[@]}'"echo "Or:"for val in "${multi[@]}"; do    echo " - $val"done

The output would be:

$ /tmp/tThe first value of the array 'multi' is ''The whole list of values is ''Or:$ /tmp/t -m "one arg with spaces"The first value of the array 'multi' is 'one arg with spaces'The whole list of values is 'one arg with spaces'Or: - one arg with spaces$ /tmp/t -m one -m "second argument" -m threeThe first value of the array 'multi' is 'one'The whole list of values is 'one second argument three'Or: - one - second argument - three


I know this question is old, but I wanted to throw this answer on here in case someone comes looking for an answer.

Shells like BASH support making directories recursively like this already, so a script isn't really needed. For instance, the original poster wanted something like:

$ foo.sh -i test -d directory -s subdirectory -s subdirectory2 -f file1 file2 file3/test/directory/subdirectory/file1/test/directory/subdirectory/file2/test/directory/subdirectory/file3/test/directory/subdirectory2/file1/test/directory/subdirectory2/file2/test/directory/subdirectory2/file3

This is easily done with this command line:

pong:~/tmp[10] rmclean$ mkdir -pv test/directory/{subdirectory,subdirectory2}/{file1,file2,file3}mkdir: created directory ‘test’mkdir: created directory ‘test/directory’mkdir: created directory ‘test/directory/subdirectory’mkdir: created directory ‘test/directory/subdirectory/file1’mkdir: created directory ‘test/directory/subdirectory/file2’mkdir: created directory ‘test/directory/subdirectory/file3’mkdir: created directory ‘test/directory/subdirectory2’mkdir: created directory ‘test/directory/subdirectory2/file1’mkdir: created directory ‘test/directory/subdirectory2/file2’mkdir: created directory ‘test/directory/subdirectory2/file3’

Or even a bit shorter:

pong:~/tmp[12] rmclean$ mkdir -pv test/directory/{subdirectory,subdirectory2}/file{1,2,3}mkdir: created directory ‘test’mkdir: created directory ‘test/directory’mkdir: created directory ‘test/directory/subdirectory’mkdir: created directory ‘test/directory/subdirectory/file1’mkdir: created directory ‘test/directory/subdirectory/file2’mkdir: created directory ‘test/directory/subdirectory/file3’mkdir: created directory ‘test/directory/subdirectory2’mkdir: created directory ‘test/directory/subdirectory2/file1’mkdir: created directory ‘test/directory/subdirectory2/file2’mkdir: created directory ‘test/directory/subdirectory2/file3’

Or shorter, with more conformity:

pong:~/tmp[14] rmclean$ mkdir -pv test/directory/subdirectory{1,2}/file{1,2,3}mkdir: created directory ‘test’mkdir: created directory ‘test/directory’mkdir: created directory ‘test/directory/subdirectory1’mkdir: created directory ‘test/directory/subdirectory1/file1’mkdir: created directory ‘test/directory/subdirectory1/file2’mkdir: created directory ‘test/directory/subdirectory1/file3’mkdir: created directory ‘test/directory/subdirectory2’mkdir: created directory ‘test/directory/subdirectory2/file1’mkdir: created directory ‘test/directory/subdirectory2/file2’mkdir: created directory ‘test/directory/subdirectory2/file3’

Or lastly, using sequences:

pong:~/tmp[16] rmclean$ mkdir -pv test/directory/subdirectory{1..2}/file{1..3}mkdir: created directory ‘test’mkdir: created directory ‘test/directory’mkdir: created directory ‘test/directory/subdirectory1’mkdir: created directory ‘test/directory/subdirectory1/file1’mkdir: created directory ‘test/directory/subdirectory1/file2’mkdir: created directory ‘test/directory/subdirectory1/file3’mkdir: created directory ‘test/directory/subdirectory2’mkdir: created directory ‘test/directory/subdirectory2/file1’mkdir: created directory ‘test/directory/subdirectory2/file2’mkdir: created directory ‘test/directory/subdirectory2/file3’


getopts options can only take zero or one argument. You might want to change your interface to remove the -f option, and just iterate over the remaining non-option arguments

usage: foo.sh -i end -d dir -s subdir file [...]

So,

while getopts ":i:d:s:" opt; do  case "$opt" in    i) initial=$OPTARG ;;    d) dir=$OPTARG ;;    s) sub=$OPTARG ;;  esacdoneshift $(( OPTIND - 1 ))path="/$initial/$dir/$sub"mkdir -p "$path"for file in "$@"; do  touch "$path/$file"done