Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie
Hi there,
There is an issue with role permissions that is being worked on at the moment.
If you are having trouble with access or permissions on regional forums please post here to get access: https://www.boards.ie/discussion/2058365403/you-do-not-have-permission-for-that#latest

Bash Scripting - Parsing Options

  • 24-11-2009 6:53pm
    #1
    Registered Users, Registered Users 2 Posts: 590 ✭✭✭


    Hi lads,

    What's the best and / or easiest way to parse options passed through to a bash script? I've had a look at getopt(s) but not sure how to separate the options from the regular arguments easily.

    For example, how would I separate the following args:
    ./myscript -n -ab someparam -c someoption
    

    into
    a=true
    b=true
    n=true
    c="someoption"
    myparam="someparam"
    

    I would imagine this to be a pretty common task.

    Any help appreciated.


Comments

  • Closed Accounts Posts: 4,564 ✭✭✭Naikon


    bman wrote: »
    Hi lads,

    What's the best and / or easiest way to parse options passed through to a bash script? I've had a look at getopt(s) but not sure how to separate the options from the regular arguments easily.

    For example, how would I separate the following args:
    ./myscript -n -ab someparam -c someoption
    
    into
    a=true
    b=true
    n=true
    c="someoption"
    myparam="someparam"
    
    I would imagine this to be a pretty common task.

    Any help appreciated.

    getopt(s) and such have their uses, but for general shell tasks, it's easier
    to just allow the shell to work it's stuff. It's more automated than you think.

    Like in C programming when you run the script a runtime array is set up
    for the script to deal with command line args.

    For reference, say an array called *argv[] (pointer to string array) is used.
    argv[0] is the name of the script being run, argv[1] is the first command line
    argument. So argv[2] would corrospond to the second string.

    The great thing about the shell is the notation to access the parameters is
    quite simple. Instead of argv[1] like in C, you simply refer to the element
    with $1 which is the first argument. $0 is always the name of the script.

    Quick breakdown:

    $# number of arguments passed as an integer
    $@ returns each argument string as seperate strings
    $* returns each argument string as one single concatenated string
    $0 name of script being executed
    $1 first argument
    $2 second argument

    So, c=$5 for example. things like "-n" are treated as params with
    increasing int values up to 9. There are workarounds for more.

    The special variables are handy if you want to do something like:
    echo "the number of parameters passed is $#"


  • Registered Users, Registered Users 2 Posts: 545 ✭✭✭ravydavygravy


    I never looked into it for bash - I normally just expect a certain number of args, and display a usage message if the number isn't correct - not exactly what you want.
    if [ $# -ne 2 ]
    then
        echo 
        echo "Usage: myscript.sh <arg1> <arg2>"
        echo "   where"
        echo "       <arg1> is blah..."
        echo "       <arg2> is blah..."
        echo
     
        exit 1
    fi
    

    Tomorrow in work, I can check a few scripts that do this better than this...

    EDIT: this any help? http://www.linux.com/archive/feature/118031


  • Closed Accounts Posts: 4,564 ✭✭✭Naikon


    Just to note, if you pass in params in this fashion:

    ./script -al -cy -zx

    you will need to use getopt to seperate the options following
    the dash. That or you come up with your own logic for parsing.

    ./script -a -l -c -y -z -x may be better for portability, or if you
    just want to avoid getopts(s) alltogether until you need more
    sophistication.


  • Moderators, Recreation & Hobbies Moderators, Science, Health & Environment Moderators, Technology & Internet Moderators Posts: 93,857 Mod ✭✭✭✭Capt'n Midnight


    just like to mention in passing that parsing batch file scripting in windows is truly painful , Iv'e used sed instead because it well nigh impossible to handle stuff like file names unless you resourted to 8.3 and even then it was hairy.


  • Closed Accounts Posts: 4,564 ✭✭✭Naikon


    just like to mention in passing that parsing batch file scripting in windows is truly painful , Iv'e used sed instead because it well nigh impossible to handle stuff like file names unless you resourted to 8.3 and even then it was hairy.

    Cygwin is your friend;) Not really a 100% reliable method though.
    I suppose PowerShell should alleviate these problems. At least in theory.


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 590 ✭✭✭bman


    Thanks for all the replies.

    I understand the basics of bash scripting and how $#, $*, $0, $1, etc. work; just don't want to have to start checking all the parameters to see if they start with a "-" and all the other messing required to break up the options.

    I'll mess about with getopt(s) and see what I come up with. I'm sure it'll only take a few lines of code anyway, but I hate reinventing the wheel. Just that this seems like something people would want to do a lot of the time.

    It's only for a small script for my own use anyway so worse comes to worse I'll hardcode it and it'll be a bit flaky but work for me :) .


  • Registered Users, Registered Users 2 Posts: 1,110 ✭✭✭Skrynesaver


    Running the following:
    #! /bin/bash
    
    while getopts "abc:n" opt; do
       case $opt in
          a )   a="true";;
          b )   b="true";;
          c )   c=$OPTARG;;
          n )   n="true";;
       esac
    done
    
    shift $(($OPTIND - 1)) # remove all options from the argument array
    
    echo "a is $a
    b is $b
    c is $c
    n is $n
    remaining args are $*";
    

    gives:
    ~$ ./test.sh -abc setting -n  filename otherfile directory
    a is true
    b is true
    c is setting
    n is true
    remaining args are filename otherfile directory
    

    Limitation is that options MUST preceed operands on the commandline ie
    ~$ test.sh filename -a will fail to set $a
    
    So having someparam among the options would require writing your own parser:(


  • Registered Users, Registered Users 2 Posts: 590 ✭✭✭bman


    Running the following:
    #! /bin/bash
    
    while getopts "abc:n" opt; do
       case $opt in
          a )   a="true";;
          b )   b="true";;
          c )   c=$OPTARG;;
          n )   n="true";;
       esac
    done
    
    shift $(($OPTIND - 1)) # remove all options from the argument array
    
    echo "a is $a
    b is $b
    c is $c
    n is $n
    remaining args are $*";
    

    gives:
    ~$ ./test.sh -abc setting -n  filename otherfile directory
    a is true
    b is true
    c is setting
    n is true
    remaining args are filename otherfile directory
    

    Limitation is that options MUST preceed operands on the commandline ie
    ~$ test.sh filename -a will fail to set $a
    
    So having someparam among the options would require writing your own parser:(

    Exactly what I was looking for. The shift $(($OPTIND -1)) command is what I needed. Will rememeber that for again.

    Having to have the regular params after the options is something I can live with :) .


Advertisement