How to catch optioned and non optioned arguments correctly?

8,281

Solution 1

It is typical for programs to force the "some_string" part to be the last argument so that .abc.ksh "some_string" -a "sample text" is an error. If you do this, then after parsing the options, $OPTIND holds the index to the last argument (the "some_string" part).

If that is not acceptable, then you can check at the beginning (before you enter the while to see if there is a non-prefixed argument. This will let you have "some_string" at the beginning and at the end. If you needed to have it in the middle, you could either not use getopts or you could have two sets of getopts. When the first one errors out, it could be due to the non-prefixed argument; get it and start a new getopts to get the remaining args. Or you can skip getopts all together and roll your own solution.

Solution 2

After capturing your options

shift $OPTIND
if [ $# -eq 1 ]; then
  some_str="$1"
else
  echo "Error: missing argument" >&2
fi
Share:
8,281

Related videos on Youtube

chanchal1987
Author by

chanchal1987

Now working in a Unix platform. Wanna get & share knowledge of Unix from/with others... Badge:

Updated on September 17, 2022

Comments

  • chanchal1987
    chanchal1987 over 1 year

    I want to write a shell script which will take some arguments with some options and print that arguments. Suppose the name of that script is abc.ksh. Usage of that script is -
    ./abc.ksh -[a <arg>|b <arg>|c|d] <some_string>
    Now I write a shell script which will take options and arguments

    #!/bin/ksh
    
    # Default Values
    vara=","
    varb=false
    varbname=""
    varc=false
    
    # Scanning inputs
    while getopts :a:b:cd option
    do
            case $option in
                    a) vara=$OPTARG;;
                       #shift $((OPTIND-1));;
                    b) varb=true
                       varbname=$OPTARG;;
                       #shift $((OPTIND-1));;
                    c) varc=true;;
                       #shift $((OPTIND-1));;
                    d) echo "Usage $0 \-[a|b|c|d] <filename>"
                       exit 0;;
                    \?) echo "Invalid option -$OPTARG. Please run '$0 -h' for help"
                        exit 1;;
                    :) echo "Option -$OPTARG requires an argument. Please run '$0 -d' for help"
                       exit 1;;
    esac
    done
    
    print "Args: $* \nvara: $vara \noptfile: $varb \nvarbname: $varbname \nvarc: $varc"
    

    Examples of Correct Inputs:

    • ./abc.ksh -a "sample text" "some_string"
    • ./abc.ksh "some_string" -a "sample text"
    • ./abc.ksh -asample\ text some_string
    • etc...

    some_string input is not catch in my script. How can I catch that?

    • mattdm
      mattdm about 13 years
      When you're getting to the level of complication where you're asking yourself this sort of question, I think it's time to shift to asking "should I be using a full scripting language instead"? Python, perl, whatever — they all have pre-existing modules for handing this gracefully and transparently.
    • Shawn J. Goff
      Shawn J. Goff about 13 years
      Posix shell is a very capable scripting language, very capable of doing what he is asking in this question. This is not at all a complicated thing.
    • Angel Todorov
      Angel Todorov about 13 years
      Perl's Getopt::Long will extract the options and leave the non-option arguments in @ARGV.
    • xenoterracide
      xenoterracide about 13 years
      just use getopt ? man getopt I've only used getopt in C so I can't really say exactly what the code should look like, but it seems like better than implementing getopt yourself.
  • chanchal1987
    chanchal1987 about 13 years
    For ./abc.ksh "some_string" -a "sample text", it will not work.
  • Angel Todorov
    Angel Todorov about 13 years
    Well for getopts, you're constrained by the tool: "Any of the following identifies the end of options: the special option --, finding an argument that does not begin with a -, or encountering an error."