4

I am new to bash scripting and I am trying to write a script with getopts so that when script.sh -sp is is invoked the URL and column and row count is printed out. And when script.sh -r option is invoked only the file type is printed.

Script :

#!/bin/bash

#define the URL 
URL='https://github.com/RamiKrispin/coronavirus/tree/master/data_raw'
#define file name
filename=$(basename "$URL")
#dowload the file
wget -q "${URL}"

while getopts ":sp:r" o; do
   case $o in
   
   sp ) echo URL: $URL #print the URL address
       awk 'BEGIN{FS=","}END{print "COLUMN NO: "NF " ROWS NO: "NR}' $filename #print the column count and row count
   r ) file $filename #print the file type 
       exit 1
        
   esac
done 

Can anyone help me understand how to use getopts correctly?

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
Olaola
  • 55
  • 6
  • note that `getopt` and `getopts` are different tools. You wrote `getopt` in the text but tagged the question with `getopts`. But you're also using `getopts` in the code, so I guess that's what you actually want. – ilkkachu Jan 02 '22 at 17:03
  • 1
    in any case, neither of them supports multi-character options. `-sp` would be the two options `-s` and `-p`. (or `-s` with the option-argument `p`, if `-s` took an opt-arg.) – ilkkachu Jan 02 '22 at 17:04

1 Answers1

7

getopts only supports single-character option names, and supports clustering: -sp is equivalent to passing -s and -p separately if -s doesn't take an argument, and it's the option -s with the argument p if -s takes an argument. This is the normal convention on Unix-like systems: after a single dash -, each character is a separate option (until an option that takes an argument); after a double dash --, everything (up to =) is the option name.

So getopts ":sp:r" o declares three options: -s and -r with no argument, and -p with an argument. You seem to only want two options and neither expects an argument, so the correct specification would be sr, and the usage would be script.sh script.sh -s or script.sh -r or script.sh -rs or script.sh -r -s etc.

while getopts sr o; do
  case $o in
    s)
      echo "URL: $URL" #print the URL address
      awk 'BEGIN{FS=","}END{print "COLUMN NO: "NF " ROWS NO: "NR}' -- "$filename" #print the column count and row count
      ;;
    r) file -- "$filename";; #print the file type
    \?) exit 3;; #invalid option
  esac
done
shift $((OPTIND - 1)) # remove options, keep non-option arguments
if [ $# -ne 0 ]; then
  echo >&2 "$0: unexpected argument: $1"
  exit 3
fi

The leading : says not to report unknown options to the user. Unknown options still cause $o to be ?. If you do that, you should print a message when $o is ?. And either way you should exit with a failure status if an option is unknown.

Other errors I fixed:

Note that it's spelled getopts, not getopt. There is a separate utility called getopt which has the same purpose but works differently and is rather harder to use. It doesn't support multiple-character options introduced by a single dash either, but it does support long options introduced by double dash.

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175