LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-17-2010, 08:05 PM   #1
JeffreyV
LQ Newbie
 
Registered: Aug 2010
Posts: 3

Rep: Reputation: 0
Bash reading arguments, most effective way


I've been reading about getopt and getopts but it doesn't seem like it's possible to parse arguments like --foo or even -foo. I've started my own script trying to achieve this, but I'm still wondering if I'm losing performance and if there is a better way to do this task.

Also I'm using the [[ =~ ]] regex syntax which seems to be available only in newer bash versions, should it be a big issue?

My bash version: GNU bash, version 4.1.7(2)-release (x86_64-unknown-linux-gnu)

My scripts goes as follows
Code:
#!/bin/bash
if [ $# -eq 0 ]; then
    printf "You need to give arguments!!!\n" >&2
    exit 1
fi

SKIP=0
for arg in "$@"; do
    [ $SKIP -eq 1 ] && SKIP=0 && continue

    if [[ $arg =~ ^--foo=.*$ ]]; then
        printf "foo = %s\n" "${arg/#*=/}"
        shift
    elif [[ $arg =~ ^--config=.*$ ]]; then
        printf "config = %s\n" "${arg/#*=/}"
        shift
    elif [[ $arg =~ ^--bar$ ]]; then
        shift
        [ -z "$1" -o "${1/%[^-]*/}" = "--" ] && printf "No argument for bar\n" >&2 && break
        printf "bar = %s\n" "$1"
        shift
        
        # Skip next one
        SKIP=1
    elif [[ $arg =~ ^-a$ ]]; then
        shift 
        [ -z "$1" -o "${1/%[^-]*/}" = "--" ] && printf "No argument for -a\n" >&2 && break

        printf "a = %s\n" "$1"
        shift
        SKIP=1
    elif [[ $arg =~ ^--playlist=.+$ ]]; then
        printf "playlist = %s\n" "${arg/#*=/}"
        shift
    else
        if [[ $arg =~ ^--.*$ ]]; then
            printf "Unknown option\n" >&2
        else
            printf "Regular argument = %s\n" "$arg"
        fi

        shift
    fi
done
When running it like this

./argument_test.sh dontuse --foo="test" normal --config="s.xml" --bar "something" --playlist="playlist.txt" -a

This is what I get as output, which I think should be the correct thing.

Regular argument = dontuse
foo = test
Regular argument = normal
config = s.xml
bar = something
playlist = playlist.txt
No argument for -a

Edit: note that --bar doesn't use the equals sign, which means it has to use the next argument in line

Last edited by JeffreyV; 08-17-2010 at 08:07 PM.
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 08-17-2010, 08:23 PM   #2
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
The bash built-in getopts can't handle long options, but the external getopt can, assuming it's the standard gnu version found in the util-linux package.

This thread appears to have some good suggestions as well.

http://stackoverflow.com/questions/4...d-line-options
 
1 members found this post helpful.
Old 08-17-2010, 08:26 PM   #3
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
You can do something similar to this:

Code:
#!/bin/bash

A=false
F=''

while [[ $# -ge 1 ]]; do
	case "$1" in
	-a)
		A=true
		;;
	--foo)
		F=$2
		shift
		;;
	--foo=*)
		F=${1#--foo=}
		;;
	*)
		# ... invalid argument?
		;;
	esac
	shift
done
 
2 members found this post helpful.
Old 08-18-2010, 03:31 AM   #4
JeffreyV
LQ Newbie
 
Registered: Aug 2010
Posts: 3

Original Poster
Rep: Reputation: 0
Thanks for the replays. Seems that combining custom code and case statements with the getopt command is a good way to do the job. But still there is always errors that can occur. I found the next page, and it seems very useful.

http://code.google.com/p/shflags/
 
Old 08-18-2010, 04:20 AM   #5
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by JeffreyV View Post
Thanks for the replays. Seems that combining custom code and case statements with the getopt command is a good way to do the job. But still there is always errors that can occur.
The one I presented doesn't use getopts... So what do you think about it?
 
Old 08-19-2010, 05:23 AM   #6
JeffreyV
LQ Newbie
 
Registered: Aug 2010
Posts: 3

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by konsolebox View Post
The one I presented doesn't use getopts... So what do you think about it?
It looks good, but like my version, you need to program something that checks for errors, if you don't specify a value.

well, getopts "abc:", will report an error if you use -c without passing a value. Which is quite useful since the user would know that he made a mistake. I guess you can wrap it all up in a function, which I will try.

There's a part that is fail proof though
Code:
	--foo=*)
		F=${1#--foo=}
		;;
Since you don't have to go mess with the argument following. A little more safe might be
--foo=[A-Za-z_-.]+

but I'm quite vague about the regex patterns that the case statement supports, so I'm going to try it out
 
Old 08-19-2010, 05:38 AM   #7
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
You can use extended pattern matching in bash.

For example:
Code:
#!/bin/bash

shopt -s extglob

A=false
F=''

while [[ $# -ge 1 ]]; do
	case "$1" in
...
	--foo)
		if [[ $# -ne 2 ]]; then
			# tell the user that it needs an argument
		else
			F=$2
			shift
		fi
		;;
	--foo=+([[:alpha:]_-.]))
		;;
...
	*)
		# ... invalid argument?
		;;
	esac
	shift
done
Notice that there's always a way to check if an argument is passed to an option.
 
  


Reply

Tags
passing



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Bash: why is word splitting not effective in an assignment catkin Programming 5 12-12-2009 12:02 PM
bash script arguments R3N3G4D3 Programming 5 11-01-2007 10:16 AM
bash history - replacing arguments Vrajgh Linux - Software 4 03-08-2006 02:36 AM
bash, passing arguments Four Linux - Newbie 3 02-06-2006 08:24 AM
bash arguments stuckinhell Programming 6 08-13-2004 05:10 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:07 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration