views:

231

answers:

3

I am trying to write a wrapper shell script that caches information every time a command is called. It only needs to store the first non-option argument. For example, in

$ mycommand -o option1 -f another --spec more arg1 arg2

I want to retrieve "arg1."

How can this be done in bash?

+1  A: 

You probably want to do something with getopt (look here or here for how to use).

Maybe save the whole command line (so you can hand it to the real tool intact), then process the arguments with getopt, grab the info you need, and launch the underling tool.

dmckee
You are referring to the Bash built-in "getopts". However, you left off the "s". The one without the "s", "getopt", refers to a standalone executable `/bin/getopt` which has similar functionality, but operates quite differently.
Dennis Williamson
IIRC, `getopts` does not handle long options, but `getopt` does.
Dennis Williamson
Is there any easy way with getopt to get arg1 specifically?
+2  A: 

Using getopt is probably the way to go.

If you wanted to see argument scanning code in bash, the non-getopt way is:

realargs="$@"
while [ $# -gt 0 ]; do
    case "$1" in
      -x | -y | -z)
        echo recognized one argument option $1 with arg $2
        shift
        ;;
      -a | -b | -c)
        echo recognized zero argument option $1, no extra shift
        ;;
      *)
        saveme=$1
        break 2
        ;;
    esac
    shift
done
set -- $realargs
echo saved word: $saveme
echo run real command: "$@"
DigitalRoss
A: 

There's no way to pick off any particular argument without examining the entire command line. The reason for this is bash's underlying assumption that any option can appear in any order, without regard to relative position on the command line. The other premise is that any option specified in the man pages in either short or long format (i.e., "-f" or "--file") will have valid, recognized use in the the execution of the command.

Your best bet is to use the example provided by DigitalRoss and either code a value for the case statement for every valid option for the command, or code for just the one(s) you want to deal with in your script and capture everything else with the "*)" construct and disregard it if it falls into that test. The trick is that if a particular option has more than one valid argument, you need to know in advance if the distinction between the arguments is positional or pattern matching based on the content of the argument. You'll also need to use the "skip" directive in order to move from one argument to the next for options with multiple arguments.