2

I want to create a script with some optional inputs parsed similar to how this respone explains but also containing a list of files with a certain extension. Example usage would be

./myscript.sh -s 25 -q 0.2 *.txt

and the script would then store 25 into the s variable, 0.2 into the q varable, and the list of all the txt files would then get individually processed. This is what I have so far

#!/bin/bash -f

# set the default values
QMAX=0.2
PROFILESIZE=50

while [[ $# > 0 ]]
do
key="$1"
case $key in
    -q|--max_q)
    QMAX="$2"
    shift # past argument
    ;;
    -s|--profile_size)
    PROFILESIZE="$2"
    shift # past argument
    ;;
esac
shift # past argument or value
done

for var in "$@"
do
    if [[ $var == *".txt" ]]
    then
        # do something on for real on each file here
        echo $QMAX $PROFILESIZE $var
    fi
done

As is, I can run with the default values by commenting out the while loop. Without commenting it out, it reads through the inputs and there are none left for the for loop to compare. I think the best option is to create a list of the files in the while loop, then use that in the for loop. Any ideas of how I would do that?

Community
  • 1
  • 1
Steven C. Howell
  • 16,902
  • 15
  • 72
  • 97

3 Answers3

3

Just append a *) case that stores the argument to an array.

*) files+=("$1") ;;

And then iterate over files instead of $@:

for file in "${files[@]}" ; do
choroba
  • 231,213
  • 25
  • 204
  • 289
1

You can use the getopts command to handle the optional arguments, leaving the remaining arguments in $@.

while getopts 's:q:' opt; do
    case $opt in
        s) PROFILESIZE=$OPTARG ;;
        q) QMAX=$OPTARG ;;
    esac
done
shift $(( OPTIND - 1 ))

This does have the drawback of not supporting long options, however.

chepner
  • 497,756
  • 71
  • 530
  • 681
0

The first sugestion is do not implement it from scratch and use "getopts/getopt" instead. However, if for some reason you can, and assuming options are always before arguments:

#!/bin/bash 

# set the default values
QMAX=0.2
PROFILESIZE=50

while [[ $# > 0 ]]
do
 key="$1"
 case $key in
 -q|--max_q)
   QMAX="$2"
   shift 2 # past argument
  ;;
  -s|--profile_size)
    PROFILESIZE="$2"
    shift 2 # past argument
   ;;
  *)
   break
   ;;

# --) 
# break
# ;;

  esac
done

for var in "$@"
do
  if [[ $var == *".txt" ]]
  then
    # do something on for real on each file here
    echo $QMAX $PROFILESIZE $var
  fi
done
pasaba por aqui
  • 3,446
  • 16
  • 40
  • Do I HAVE to have the options always before the arguments? Without the `break` statement, couldn't the input be in any order? – Steven C. Howell May 29 '15 at 18:28
  • If arguments and options are mixed, then you need an auxiliar array as suggested by @choroba. However, it is not very usual, and even not good to allow them mixed. In fact, it is usual allow an optional "---" with the meaning of "end of options, start of arguments". In this way, an argument can have the same name than an option. – pasaba por aqui May 29 '15 at 18:30