2

I'm writing a large number of Bash functions that are to be capable of acquiring different pieces of information from the command line passed using positional arguments or named arguments (provided by getopts). The idea is that positional arguments are to be used largely for briskness and direct human control while named arguments are to be used largely for clarity and control by other functions. To illustrate how I am thinking about this, consider a function that can convert from one thing to another. This function can be used, broadly speaking, in a quick mode or in an advanced mode. In the quick mode, few arguments are specified and, generally, are positional arguments, while in the advanced mode, many arguments can be specified and, generally, are named arguments. For examples...

quick mode

This mode can be used in a manner such as the following:

function fileName1 fileName2

It converts one file to another using internal assumptions and measurements made autonomously.

advanced mode

This mode can be used in a manner such as the following:

function -i fileName1 -o fileName2 -m -r 100 -v

This mode can be used also in a manner such as the following:

function -m -v fileName1 fileName2 -r 100

Note that -v accepts no argument. It is an option only (specifying something such as verbosity).


So, the logic in this case would be that the first positional argument is assumed to be fileName1 and the second positional argument is assumed to be fileName2 unless either of these file names are specified using the -i or -o options, in which case they are used because they are given higher priority (and the first and second positional arguments are ignored).

I ask for suggestions and guidance in implementing these types of requirements in as general a way as possible because this approach is to be applied to a library of over 150 functions.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
d3pd
  • 7,935
  • 24
  • 76
  • 127
  • possible duplicate of [How can a Bash function detect whether it is being used with positional or named arguments?](http://stackoverflow.com/questions/20642784/how-can-a-bash-function-detect-whether-it-is-being-used-with-positional-or-named) – Michael Kropat Dec 24 '13 at 19:14
  • No: the question you mentioned concerns identification of one of two types of usage of argument, while the current question concerns the prioritisation of arguments designed for receiving the same information. – d3pd Dec 24 '13 at 19:19
  • Ah, I see the distinction now, after reading the earlier question closely. Sorry that I only glossed over your first question. – Michael Kropat Dec 24 '13 at 19:25

3 Answers3

2

Be aware that if you use getopts, all positional arguments must come after any options. A second caveat is that if you use getopts to parse arguments to a function, you must reset the global OPTIND variable to 1 after parsing any options. Otherwise I think the solution is straightforward:

argparse.sh

#!/usr/bin/env bash

func() {
    local args=$*
    local input output verbose
    local r="unset" m=0 verbose=0

    while getopts i:o:mr:v opt; do
        case "$opt" in
            i) input="$OPTARG" ;;
            o) output="$OPTARG" ;;
            r) r="$OPTARG" ;;
            m) m=1 ;;
            v) verbose=1 ;;
        esac
    done
    shift $((OPTIND-1))
    OPTIND=1    # reset global variable

    [[ $input ]]  || input=$1
    [[ $output ]] || output=$2

    echo "=== func $args ==="
    echo "input: $input"
    echo "output: $output"
    echo "verbose: $verbose"
    echo "r: $r"
    echo "m: $m"
    echo
}

func fileName1 fileName2
func -i fileName1 -o fileName2 -m -r 100 -v
func -m -v -r 100 fileName1 fileName2

Output

=== func fileName1 fileName2 ===
input: fileName1
output: fileName2
verbose: 0
r: unset
m: 0

=== func -i fileName1 -o fileName2 -m -r 100 -v ===
input: fileName1
output: fileName2
verbose: 1
r: 100
m: 1

=== func -m -v -r 100 fileName1 fileName2 ===
input: fileName1
output: fileName2
verbose: 1
r: 100
m: 1
Community
  • 1
  • 1
Michael Kropat
  • 14,557
  • 12
  • 70
  • 91
  • Thank you very much for your suggestions and for your efficient code. I hadn't seen the double square brackets tests without the ```if``` statements before, but I see how it makes sense. What I'm trying to do is effectively to allow for interpretation of arguments that are not acceptable to ```getopts``` with its specified option string. Then, I want to address conflicts arising using priority rules. Perhaps [my most recent question](http://stackoverflow.com/questions/20779195/how-to-produce-a-list-of-all-parameters-not-accepted-by-getopts) could clarify somewhat. – d3pd Dec 26 '13 at 04:49
1

I used @getopt@ to parse command line arguments. I do not remember right now if it solves your problem. But it was useful for me.

http://linux.die.net/man/1/getopt

Nicolai
  • 5,489
  • 1
  • 24
  • 31
  • Thanks for the suggestion. I'm not aware of a way by which ```getopt``` can return arguments that it has not accepted. – d3pd Dec 26 '13 at 04:40
1

adapted from http://rsalveti.wordpress.com/2007/04/03/bash-parsing-arguments-with-getopts/

How about always trying to getopts first, and if that fails revert to just using $1/$2/etc.

TEST=
SERVER=
PASSWD=
VERBOSE=
while getopts “ht:r:p:v” OPTION
do
     case $OPTION in
         h)
             usage
             exit 1
             ;;
         t)
             TEST=$OPTARG
             ;;
         r)
             SERVER=$OPTARG
             ;;
         p)
             PASSWD=$OPTARG
             ;;
         v)
             VERBOSE=1
             ;;
         ?)
             usage
             exit
             ;;
     esac
done

if [[ -z $TEST ]] || [[ -z $SERVER ]] || [[ -z $PASSWD ]]
then
     // Set variables from $1/$2/etc....
fi
tinkertime
  • 2,972
  • 4
  • 30
  • 45
  • Thank you very much for your suggestion. What you suggest does make a kind of explicit sense, but what I'm trying to do is allow for interpretation of arguments that are not acceptable to ```getopts``` with its specified option string - *without discarding successful ```getopts``` parsing*. Then, I want to address conflicts arising using priority rules. Perhaps [my most recent question](http://stackoverflow.com/questions/20779195/how-to-produce-a-list-of-all-parameters-not-accepted-by-getopts) could clarify somewhat. – d3pd Dec 26 '13 at 04:52