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?

2
  • 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 2, 2022 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 2, 2022 at 17:04

1 Answer 1

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.

You must log in to answer this question.

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