Linux - SoftwareThis forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I'm still a bit of a novice when it comes to bash scripting, and am having problems processing arguments from the command line. I tend to run my script as:
Code:
./myscript file1 file2 or ./myscript action file1 file2
If I run the script with no action - just the files - the script runs the default action.
I want to say:
(1) if one or more files are listed, with no action, then process with default action
(2) if an action is given, along with one or more files, then process the files with this action
(3) action, if given must be $1
Can anyone help?
My current incarnation looks like this:
Code:
if [ -f "$1" -o -d "$1" ] # if this is a file or directory
then
filelist="$@"
action1 # default action, process files
elif [ ! -f "$1" -a ! -d "$1" ] # if it is NOT a file AND not a directory, it's an action.
then
action="$1"
filelist="$@"
if [ $action == "action1" ] # default action when called explicitly
then
action1 # calls the function to process the files
elif [ $action == "action2" ] # performs opposite action on files
then
action2
# the rest of these are just helpful actions, but do not actually process files
elif [ $action == "action3" ]
then
action3
elif [ $action == "action4" ]
then
action4
elif [ $action == "action5" ]
then
action5
elif [ $action == "action6" ]
then
action6
else
echo "$action is invalid"
fi
else
echo "Not an option"
fi
Two problems:
(1) Even though I have checked my arguments here, I still have to strip $1 from those functions that do process the files anyway.
(2) The action1 function works great, but the action2 function breaks, even though it processes the files in reverse from action1.
This part of action1 and action2 are exactly alike:
Code:
action()
{
for f in $filelist # processes $1 (the action), along with the files.
do
if [ -f "$f" -o -d "$f" ] # this is to prevent processing $1
Is getopts a better approach?
Thanks!
Last edited by dcparris; 03-16-2012 at 06:56 PM.
Reason: Clarify question
(1) Even though I have checked my arguments here, I still have to strip $1 from those functions that do process the files anyway.
You can use shift to get rid of the first argument (simplified):
Code:
#!/bin/bash
if [ -f "$1" -o -d "$1" ]
then
action="default action"
filelist="$@"
else
action="$1"
shift # strip first argument
filelist="$@"
fi
echo $action
echo $filelist
exit 0
Quote:
2) The action1 function works great, but the action2 function breaks, even though it processes the files in reverse from action1.
Maybe this will work (simplified):
Code:
#!/bin/bash
doAction() {
Action="$1" # store $1 (= action) in human readable variable
Files="$2" # store $2 (= file(s)) in human readable variable
# the next part is a case/esac construct
case ${Action} in
action1) echo "do action 1 on $Files";;
action2) echo "do action 2 on $Files";;
* ) echo "Action ($Action) is not valid....";;
esac
}
if [ -f "$1" -o -d "$1" ]
then
action="action1"
filelist="$@"
else
action="$1"
shift
filelist="$@"
fi
doAction "$action" "$filelist" # start function using action and file(s)
exit 0
Quote:
Is getopts a better approach?
Not necessarily better, you stll need to tell getops what is correct and what is not. With a limited amount of options I tend not to use getops (but that is a personal choice).
Many Thanks! Shift works. I thought I was not understanding the use of shift, since I could not get action2 to work for the life of me. Through process of elimination, I now realize the problem lay elsewhere (namely inside action2), specifically the file/directory test. But I have learned a lot about hunting bugs - and processing command line arguments.
I never really know, short of actually writing it out both ways (which seems a bit excessive). Getopts can result in cleaner-looking code, if you structure the bit that actually deals with the options well, but 'cleaner' isn't always a synonym for 'better'. The getopts approach hides some of the complexity in getopts out of the way of anyone looking at the script, which feels like an advantage, but unless you understand exactly what getopts does, is it really such an advantage?
I'd have to say that its too close to call, in general, but that you might find that one approach suits your style more than the other.
(It is a stupid answer, because the only thing here is links, and all can be found by the use of a search engine. I still hope that they are valuable, though, because you don't have to sort through all sorts of rubbish to get there.)
is easier to write initially when you have a pro-forma skeleton.
deals with no space between the option letters and their arguments.
encourages complete error trapping.
is easier to extend when the script is further developed.
FWIW here is my pro-forma/boilerplate.
Code:
lf=$'\n'
# Set defaults that may be overriden by command line parsing
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse command line
# ~~~~~~~~~~~~~~~~~~
emsg=''
while getopts dhVo: opt 2>/dev/null
do
case $opt in
d )
debug='YES'
;;
h )
usage -v
exit 0
;;
V )
echo "$prgnam version $prg_ver"
exit 0
;;
o )
o_optarg="$OPTARG"
;;
* )
emsg="${lf}Invalid option '$opt'"
esac
done
# Test for extra arguments
# ~~~~~~~~~~~~~~~~~~~~~~~~
shift $(( $OPTIND-1 ))
if [[ $* != '' ]]; then
emsg="${lf}Invalid extra argument(s) '$*'"
fi
# Test for mandatory options not set
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [[ ${o_optarg:-} = '' ]]; then
emsg="${lf}Mandatory option -o not given"
fi
# Report any errors
# ~~~~~~~~~~~~~~~~~
if [[ $emsg != '' ]]; then
echo "$emsg" >&2
usage
exit 1
fi
echo "DEBUG: o_optarg is '$o_optarg'"
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.