Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving multiple arguments for a single option using getopts in Bash

I need help with getopts.

I created a Bash script which looks like this when run:

$ foo.sh -i env -d directory -s subdirectory -f file

It works correctly when handling one argument from each flag. But when I invoke several arguments from each flag I am not sure how to pull the multiple variable information out of the variables in getopts.

while getopts ":i:d:s:f:" opt    do      case $opt in         i ) initial=$OPTARG;;         d ) dir=$OPTARG;;         s ) sub=$OPTARG;;         f ) files=$OPTARG;;       esac done 

After grabbing the options I then want to build directory structures from the variables

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

Then the directory structure would be

/test/directory/subdirectory/file1 /test/directory/subdirectory/file2 /test/directory/subdirectory/file3 /test/directory/subdirectory2/file1 /test/directory/subdirectory2/file2 /test/directory/subdirectory2/file3 

Any ideas?

like image 782
vegasbrianc Avatar asked Sep 23 '11 13:09

vegasbrianc


People also ask

What does getopts mean in Bash?

On Unix-like operating systems, getopts is a builtin command of the Bash shell. It parses command options and arguments, such as those passed to a shell script. How it works. Specifying the optstring. Verbose error checking.

Should I use getopt or getopts?

The main differences between getopts and getopt are as follows: getopt does not handle empty flag arguments well; getopts does. getopts is included in the Bourne shell and Bash; getopt needs to be installed separately. getopt allows for the parsing of long options ( --help instead of -h ); getopts does not.

What is Optind in getopts?

According to man getopts , OPTIND is the index of the next argument to be processed (starting index is 1).

What is the purpose of getopts command?

Description. The getopts command is a Korn/POSIX Shell built-in command that retrieves options and option-arguments from a list of parameters. An option begins with a + (plus sign) or a - (minus sign) followed by a character. An option that does not begin with either a + or a - ends the OptionString.


2 Answers

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/bash  while getopts "m:" opt; do     case $opt in         m) multi+=("$OPTARG");;         #...     esac done shift $((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/t The 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 three The first value of the array 'multi' is 'one' The whole list of values is 'one second argument three' Or:  - one  - second argument  - three 
like image 50
mivk Avatar answered Oct 09 '22 12:10

mivk


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’ 
like image 23
Ryan Avatar answered Oct 09 '22 12:10

Ryan