1

I want to take two arguments and a third optional one for a script I am developing. I am new working with bash so I have been copying and trying to understand the following code that does what I want (I guess)

while [[ $# -gt 0 ]]; do
   case $1 in
   -f1|-fasta1)
       FASTA1=$2
       shift
       ;;
   -f1=*|-fasta1=*)
       FASTA1=${1#*=}
       ;;
   -d|-directory)
       DIRECTORY=$2
       shift
       ;;
   -d=*|-directory=*)
       DIRECTORY=${1#*=}
       ;;
   -f2|fasta2)
       FASTA2=$2
       shift
       ;;
   -f2=*|-fasta2=*)
       FASTA2=${1#*=}
       ;;
   -*)
       echo "Invalid option: $1" >&2
       exit 1
       ;;
   --)
       # Do FILES+=("${@:2}") maybe
       break
       ;;
   *)
       # TODO
       # Do FILES+=("$1") maybe
       ;;
   esac

   shift
done

The thing is that there is many part of this code that I dont really understand what is for for instance the -gt or the 1#*= or why each argument needs to be written twice line one

-f1|-fasta1)
       FASTA1=$2
       shift

and two

 -f1=*|-fasta1=*)
       FASTA1=${1#*=}

Someone could tell me where I can find explanation for this. I have been reading in tutorial but with easier examples I cant understand this.

1 Answer 1

4

The code you are posting is indeed a very "manual" way of parsing command-line arguments. It is usually considered good practice to use getopt and/or getopt_long for that purpose. Note also that having "long options" introduced by only one dash (as in -fasta1) is unusual; normally you would expect them to be preceded by two dashes (see also this question on the format of command-line arguments).

That said, most of what you are seeing is basic shell syntax, namely string manipulation, case statements and test constructs.

The [[ $# -gt 0 ]] statement is simply a test in which the special paramter $#, containing the number of command-line arguments, is checked whether it is greater than (-gt) zero. This is used as condition in the while loop because the parameter handling routine uses the shift statements that discards the first command-line parameter after it is processed, thereby reducing the number of arguments successively. Once all parameters are processed, the option handling loop needs to finish.

As for the other questions: The program wants to allow the user to specify the first FASTA file in a variable of possible syntaxes, namely:

-f1 <filename>
-fasta1 <filename>
-f1=<filename>
-fasta1=<filename>

The program does so by iterating over the command-line parameters "manually", i.e. it always checks what the "current first" argument ($1) is, interprets it, and then discards it using the shift command (whereby all command-line arguments move "one number up").

In order to accept both the "short" and "long" option names, the case statement accepts both -f1 and -fasta1 (for the space-separated syntax), and both -f1=* and -fasta1=* (for the =-separated syntax) as current argument. However, it needs to treat the "value" part of the option differently depending on the syntax.

  • For the space-separated syntax, the statement of the first FASTA file is recognized by $1 being either -f1 or -fasta1. The program knows that the "value" of the option is then in the next command-line parameter $2, so it assigns the content of $2 to the FASTA1 variable. An additional shift is needed to discard that next command-line parameter, too, since it is already handled in this iteration.
  • For the =-separated syntax, the statement of the first FASTA file is recognized by $1 matching either -f1=* or -fasta1=*. This means that the "value" of the option is part of the current value of $1 and needs to be extracted by string manipulation. The statement
    ${variablename#pattern}
    
    means "return the value of $variablename, but remove the shortest string that matches pattern from the beginning of the value". So,
    ${1#*=}
    
    means "return the value of $1, but remove the shortest string that matches *= from the beginning", effectively stripping -f1= or -fasta1= from the value. What remains is the filename.

If you want to dive deeper into shell programming, I would recommend GreyCat&Lhunath's Bash Guide for further reading.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .