Question

I have a (bash) shell script myBaseScript.sh, with the following signature:

myBaseScript.sh [OPTIONS] FILE1 [FILE2 ...]

This script myBaseScript.sh parses the options via getopts, like so:

while getopts ":hi:m:s:t:v:" opt; do
    #...
done

shift $(($OPTIND-1))
FILES=("$@")

Now I wish to create a script mySuperScript.sh, which calls myBaseScript.sh, allowing options to be forwarded to the base script:

mySuperScript.sh [OPTIONS] DIR1 [DIR2 ...]

where [OPTIONS] are the options used in myBaseScript.sh; they are not used in mySuperScript.sh.

The script mySuperScript.sh is to crawl through all directories DIR1, [DIR2], etc., compiling a list of valid files ${FILES[@]}, to be passed on to myBaseScript.sh.

Right now I have this in mySuperScript.sh:

myBaseScript.sh "$@" "${FILES[@]}"

where ${FILES[@]} is a list of files in the current path. In other words, this allows for

mySuperScript.sh [OPTIONS] 

but not for any optional DIR1, [DIR2], etc.

I could use

allOpts=("$@")
while getopts ":hi:m:s:t:v:" opt; do echo. > /dev/null; done
shift $(($OPTIND-1))    
DIRS=("$@")

and then pass the first $OPTIND entries of $allOpts as [OPTIONS] to myBaseScript.sh. But that seems excessively complicated, and moreover, it necessitates duplicating the list of valid options to myBaseScript.sh, which is a managerial nightmare.

I could also create a new script, dedicated to parsing these options. But that too seems a bit awkward, as it creates a dependency in myBaseScript.sh which was not there before...

So, what is the cleanest way to do this?

Was it helpful?

Solution

I don't know your entire usecase but if your goal is simply to support both files and directories then you can just use a single script which checks if an argument is a directory and crawls it.

For example:

#!/bin/bash

crawl_dir() {
    dir="$1"
    find "$dir" -type f
}

# parse options
while getopts ":hi:m:s:t:v:" opt; do
    echo ...
done
shift $(($OPTIND-1))

args=( "$@" )

# parse arguments
files=()
for arg in "${args[@]}"
do
    if [[ -d "$arg" ]]
    then
        files+=( $(crawl_dir "$arg") )
    else
        files+="$arg"
    fi
done

# now you have an array of files to process
process "${files[@]}"

OTHER TIPS

If you call mySuperScript.sh with an additional marker between the [OPTIONS] and the list of directories:

mySuperScript.sh [OPTIONS] -- DIR1 [DIR2 ...]

Then you can iterate over the arguments and collection the options into a variable. Something like:

while [ "$1" -ne "--" ]; do
  OPTIONS="$OPTIONS $1"
  shift
done
shift

Then you can later on call:

myBaseScript.sh $OPTIONS $some_list_of_files

This works fine as long as you're not trying to handle optional arguments containing spaces.

On a more practical note, this is generally when I start looking at Python.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top