bash case statement with multiple command line options
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
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.
bash case statement with multiple command line options
I'm trying to write a script which will read one or more command line options and run different parts of the script accordingly. I've had a look at http://tldp.org/LDP/Bash-Beginners-G...ect_07_03.html, and it seems a case statment is ideal, so:
Ah, yes. I'd thought of that, it's just that I wanted to avoid duplication within the script since I'm in the process of testing certain parameters to determine which is the best, and the equivalents of my_processing_commands_here and my_imaging_commands_here are quite long.
Could I create two variables: processing and imaging, which I set as all the processing commands, and all the imaging commands, which I then call from within the case statements, which would enable me to have a shorter version of the 'both' case?
In the case statement, if I changed the $1 to $*, would that have the effect of reading in any variable I've put after the script name when I call it from the command line? So, that the following would be synonymous:
Code:
myscript.sh -p -i
myscript.sh -i -p
What I suppose I want to know is is the $1 the first option, $2 the second etc.? And would $* mean any option?
Ok, so if I need to run the script with only certain of the options - sometimes with only one, sometimes with more than one, and sometimes with all of them, then my case statement (which has evolved a little since I first posted) would look a bit like this?
Code:
while test -n "$@"; do
case "$@" in
"")
echo "Usage: $0 [-p|--preprocess] [-g|--gradient] [-i|--image] [-l|--plot]"
RETVAL=1
;;
--preprocess|-p)
preprocessing="true"
shift
;;
--gradient|-g)
gradient="true"
shift
;;
--image|-i)
imaging="true"
shift
;;
--plot|-l)
plot="true"
shift
;;
esac
done
The bit I'm least sure about is the while test -n "$@"; do... - should that be $1?
No, it is "$1" in both while and case statements.
It will test one argument at time, and this argument is always the first argument.
The "shift" statement will (guess what ?) shift the 2nd argument to the first position, so when at begin of loop, the 2nd argument will be in $1 again until there is no arguments left to test.
This is a basic construction for parsing the command line.
There are others options too. If you are interested, there is the command getopt which is part of util-linux rpm package in my opensuse distro.
It is similar to getopt system call available to C programmers and offer a very sophisticate way to parse the command line.
There's still one small thing, and that's when there are no options specified after the script, it doesn't spit out the usage. Obviously not a major bug from my perspective, but it'd be nice to know how to get that to work too
Otherwise, it's working like a charm. Just in case anyone's interested, here's the whole script (maybe someone might need it?...)
For info, the majority of the programs being called are part of the GMT (Generic Mapping Tools) suite, which I believe is included in Ubuntu these days. We use it quite extensively here at work.
Code:
#!/bin/bash
# script to roughly plot the bathy from boldner cliff
##----------------------------------------------------------------------------##
# all the gumpf
area=-R606924/609044/5618607/5619770
proj=-Jx0.01
# i/o
infile=./raw_data/all_bathy.txt
outfile=./images/bouldnor_cliff.ps
# all the prettifying type stuff
gmtset ANNOT_FONT_SIZE 10
gmtset LABEL_FONT_SIZE 12
gmtset HEADER_FONT_SIZE 16
gmtset ANNOT_FONT_SIZE_SECONDARY 10
# number formatting thing
gmtset D_FORMAT %7.9lg
do_preprocessing() {
echo -n "blockmeaning... "
blockmean $area $infile -I0.75 > ./raw_data/bmd_all_bathy.txt
echo "done!"
}
do_surfacing() {
echo -n "surfacing... "
surface $area -I0.75 -T0.25 ./raw_data/bmd_all_bathy.txt -Ghwtma_surface.grd
echo "done!"
}
do_gradient() {
# illumination
echo -n "gradient... "
grdgradient hwtma_surface.grd -A250 -N3 -Ghwtma_grad.grd
echo -n "mask... "
# make a mask and remove the interpolated areas
grdmask $area ./raw_data/bmd_all_bathy.txt \
-Ghwtma_mask.grd -I0.75 -N/NaN/1/1 -S1
grdmath hwtma_surface.grd hwtma_mask.grd MUL = hwtma_bathy.grd
echo "done!"
}
do_imaging() {
# basemap
echo -n "imaging... "
psbasemap $area $proj \
-Ba200f100:"Eastings":/a200f100:"Northings"::."Bouldnor Cliff Swath Bathymetry":WeSn \
-Xc -Yc -K > $outfile
# colour palette
makecpt -Cwysiwyg -T-1/15/0.5 -I -Z > .hwtma.cpt
# colour scale
psscale -D22/5.5/5/0.5 -B2 -I-1/1 -C.hwtma.cpt -O -K >> $outfile
# the image
grdimage $area $proj -Bg200 -Ihwtma_grad.grd -C.hwtma.cpt \
hwtma_bathy.grd -O >> $outfile
echo "done!"
}
do_plot() {
echo -n "conversion... "
ps2pdf -sPAPERSIZE=a4 $outfile
gs -sDEVICE=jpeg -r200 -sPAPERSIZE=a4 -dBATCH -dNOPAUSE \
-sOutputFile=bouldnor_cliff.jpg $outfile > /dev/null
echo "done!"
}
# set all script variables
RETVAL=0
preprocessing="false"
gradient="false"
imaging="false"
plot="false"
##----------------------------------------------------------------------------##
# start the case-ing
while test -n "$1"; do
case "$1" in
"")
echo "Usage: $0 [-p|--preprocess] [-s|--surface] [-g|--gradient] [-i|--image] [-l|--plot]"
RETVAL=1
;;
--preprocess|-p)
preprocessing="true"
shift
;;
--surface|-s)
surfacing="true"
shift
;;
--gradient|-g)
gradient="true"
shift
;;
--image|-i)
imaging="true"
shift
;;
--plot|-l)
plot="true"
shift
;;
esac
done
# pick which one to do based on the result of the case statement
if [ "$preprocessing" == "true" ]; then
do_preprocessing
fi
if [ "$surfacing" == "true" ]; then
do_surfacing
fi
if [ "$gradient" == "true" ]; then
do_gradient
fi
if [ "$imaging" == "true" ]; then
do_imaging
fi
if [ "$plot" == "true" ]; then
do_plot
fi
exit $RETVAL
test how many arguments are in the command line and print the usage if there is less than a minimum. In this case I think you want at least one argument, right ?
Code:
usage() {
echo "Usage: $0 [-p|--preprocessing] [-s|--surface]...."
exit 1
}
if [ $# -lt 1 ]; then
echo "There are no enought arguments in command line." > /dev/stderr
usage
fi
...your program follows here
# script to roughly plot the bathy from boldner cliff
##----------------------------------------------------------------------------##
# all the gumpf
inside the case statement, remove the option "". It does not make sense anymore.
I've got this script which I shall use as a template for my future scripts. It'll save me an enormous amount of commenting large sections out, as I used to do!
A general unix command should works without any options. Options are not mandatory.
In your program, the user must choose an option, but it shouldn't.
So, to make it more like a regular unix command, set a default option. If the user does not specify one, the default option wins.
let say, this default option is "preprocess":
Code:
usage() {
echo "Usage: $0 [-p|--preprocessing] [-s|--surface]...."
echo "in absence of any options, the default option is preprocessing."
exit 1
}
preprocessing="false"
gradient="false"
imaging="false"
plot="false"
if [ $# -lt 1 ]; then
preprocessing="true"
fi
...your program follows here
# script to roughly plot the bathy from boldner cliff
##----------------------------------------------------------------------------##
# all the gumpf
I've implemented a default, as you've suggested, which just runs all the commands. That way something useful will come out at the end, even if it does take an age.
We (my colleague has now taken an interest in what I've written!) have begun to expand this so that the script will do this process for almost all types of input data we work with, so it's automating some of the variables (such as $area and $proj) which I had originally manually set.
I may try and get it so that I can read in a file from the command line (so that the variables $infile and $outfile can be specified). The ultimate aim is to be able to run the script as though it were a program without editing the actual script itself at all, whilst still maintaining some of the flexibility. Obvioiusly there is a trade-off to be made, but I'm sure we can get it so that the trade-off isn't too great.
It's getting to be a bit of a monster now, but it should save time in future (at least that's what I'll tell my supervisor!... )
Once more, thanks for all your help marozsas and makyo.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.