Variable assignment inside a case statement (bash) [duplicate] - bash

This question already has answers here:
Command not found error in Bash variable assignment
(5 answers)
Closed 2 years ago.
I am trying to parse incoming options in my bash script, and save the values in variables.
This is my code:
#!/bin/bash
while getopts "H:w:c" flag
do
# echo $flag $OPTIND $OPTARG
case $flag in
H) host = "$OPTARG"
;;
w) warning = "$OPTARG"
;;
c) critical = "$OPTARG"
;;
esac
done
However, the statements inside 'case' must be command-line commands, so I can't make the wanted assignment. What is the right way to do this?

Remove the spaces around the = operators:
case "$flag" in
H) host="$OPTARG" ;;
w) warning="$OPTARG" ;;
c) critical="$OPTARG" ;;
esac

You also need to change the optstring - The c option needs to be followed by a colon if you want to collect its argument:
while getopts "H:w:c:" flag

I took a slightly different approach when creating a script to practice if/then/else and case statements. BTW, if you install cowsay;
sudo apt-get install cowsay
and fortune;
sudo apt-get install fortune
you can use this script as is and then play around with it to get used to making assignments in case statements or using if/then/else statements.
#!/bin/bash
echo "Choose a character from the following list:"
echo
echo "1) Beavis"
echo "2) Cow Hitting a Bong"
echo "3) Calvin"
echo "4) Daemon"
echo "5) Dragon and Cow"
echo "6) Ghostbusters"
echo "7) Ren"
echo "8) Stimpy"
echo "9) Sodomized Sheep"
echo "0) Mech and Cow"
#
echo
read character
echo
#
case "$character" in
"1") file="beavis.zen.cow" ;;
"2") file="bong.cow" ;;
"3") file="calvin.cow" ;;
"4") file="daemon.cow" ;;
"5") file="dragon-and-cow.cow" ;;
"6") file="ghostbusters.cow" ;;
"7") file="ren.cow" ;;
"8") file="stimpy.cow" ;;
"9") file="sodomized-sheep.cow" ;;
"0") file="mech-and-cow.cow" ;;
*) clear; ./cowsay.sh;
esac
#
#echo "var 'file' == $file"
echo "What would you like your character to say?"
echo "Alternatively, if you want your character to"
echo "read you your fortune, type 'fortune'."
read input_string
#
if [ $input_string = fortune ] ; then
clear; $input_string | cowsay -f /usr/share/cowsay/cows/$file
else
clear; cowsay -f /usr/share/cowsay/cows/$file $input_string
fi
~

Related

Shell script with parameters?

I have a shell script that takes parameters, below is the code..
Right now it will only accept parameters if passed if called like this: script.sh --mode=load (or -m=load)
Is there a way to modify this so that it can be called with or without the "=" sign, so that I can call: script.sh --mode load (or -m load)
Ideally needs to work in pure bash as I don't have access to install additional tools, etc.
for i in "$#"
do
case $i in
-m=*|--mode=*)
MODE="${i#*=}"
if [[ $MODE =~ ^(dump|load)$ ]]; then
echo "" > /dev/null
else
bark "Invalid --mode set, set this to dump or load.";
exit 1
fi
;;
-p=*|--db-path=*)
DBPATH="${i#*=}"
;;
-d=*|--dump-dir=*)
DUMPDIR="${i#*=}"
;;
-l=*|--list-file=*)
TABLES="${i#*=}"
# check if file exists on disk
if [ -e $TABLES ]
then
echo "" >> /dev/null
else
bark "Table file not found!";
exit 1
fi
;;
-t=*|--tenant-name=*)
TENANT="${i#*=}"
# check if tenant is correct
if [[ $TENANT =~ ^($TENANT_LIST)$ ]]; then
echo "" >> /dev/null
else
bark "Tenant name does not match, aborting.";
exit 1
fi
;;
-s|--shared)
SHARED=YES
;;
*) usage # unknown option
;;
esac
done
My bash version:
bash --version
GNU bash, version 4.3.22(1)-release (powerpc-ibm-aix5.1.0.0)
Loop on $#. When $1 is "-m", do a shift. So in the next loop $1 will now be the argument to the -m option.
script.sh --mode load
# FIRST LOOP
$# is "--mode load"
$1 is "--mode"
shift
# SECOND LOOP
$# is "load"
$1 is "load"
This is also useful if you can specify many arguments instead of just one like you have right now. Error checking should be done to validate your argument values, and if a user did script.sh --mode with no other argument.
Don't reinvent the wheel.
If you're OK with just 1 character options, use the bash builtin getopts
#!/bin/bash
while getopts :m:p:d:l:t:s opt; do
case $opt in
m) mode=$OPTARG ;;
p) dbpath=$OPTARG ;;
d) dumpdir=$OPTARG ;;
l) tables=$OPTARG
# test file existence
;;
t) tenant=$OPTARG
# test tenant
;;
s) shared=YES ;;
:) echo "Missing argument for option -$OPTARG" >&2
exit 2
;;
*) echo "Invalid option -$OPTARG" >&2
exit 2
;;
esac
done
shift $((OPTIND - 1))
cat << SHOW_VARS
I have:
mode=$mode
dbpath=$dbpath
dumpdir=$dumpdir
tables=$tables
tenant=$tenant
shared=$shared
rest of args=$*
SHOW_VARS
Otherwise, you may be able to use the external getopt program to help parse your args. I don't have an AIX box to test on, so YMMV
tempargs=$(
getopt \
-o m:d:l:t:s \
--long mode:,db-path:,dump-dir:,list-file:,tenant-name:,shared \
-- "$#"
)
if [[ $? -ne 0 ]]; then echo "Error..." >&2; exit 2; fi
eval set -- "$tempargs"
while true; do
case $1 in
-m|--mode) mode=$2; shift 2;;
-p|--db-path) dbpath=$2; shift 2;;
-d|--dump-dir) dumpdir=$2; shift 2;;
-l|--list-file) tables=$2
# test file existence
shift 2
;;
-t|--tenant-name) tenant=$2
# test tenant
shift 2
;;
-s|--shared) shared=YES; shift;;
--) shift; break ;;
*) echo "Error..." >&2; exit 2 ;;
esac
done

getopts not iterating on shell script

I'm experiencing an issue with a getopts on a bash script. In particular the code below seems not to work with more than 1 parameter.
If I do:
./script.sh - t template-name -m terminal-name
only template variable is populated while if i do
./script.sh - m terminal-name -t template-name
only terminal is pupulated
while getopts ":m:t:r:" optname;
do
case "${optname}" in
"m")
terminal = $OPTARG
;;
"t")
echo "Using template: $OPTARG"
template = "$(cat $OPTARG)"
;;
"r")
reboot="yes"
tput setaf 1; echo "TERMINAL WILL BE REBOOTED WHEN DONE!!"
;;
"?")
echo "Unknown option $OPTARG"
;;
":")
echo "No argument value for option $OPTARG"
;;
*)
# Should not occur
echo "Unknown error while processing options"
;;
esac
done
shift $((OPTIND-1))
I believe that if you are using getopts in a while you do not need the shift.

run shell script with or without options

I would like to run a shell script that will print either 'yesterday' or 'tomorrow' based on the option that is provided at the command line. If the option is -y, then the output should be 'yesterday', otherwise is 'tomorrow'. In addition I would like to add the option help -h which will print the syntax of the script.
I made the script as:
#! /bin/bash
h= y=
while getopt :f:vql opt
do
case $opt in
y) setday=true
;;
h) tohelp=true
;;
esac
done
shift $((OPTIND - 1))
if [setday=true]
NAME=$yesterday
else
NAME=$tomorrow
fi
if [tohelp=true]
MSG=$'runner [-y]'
echo $NAME
echo $MSG
but when I run it, I simply get an infinite loop that prints
-- opt
-- opt
-- opt
etc
What I am getting wrong?
This should work.
#!/bin/bash
setday=false
tohelp=false
yesterday="Yesterday"
tomorrow="Tomorrow"
for i in "$#"
do
case $i in
-y)
setday=true
shift
;;
-h)
tohelp=true
shift
;;
esac
shift
done
if [ $setday = true ]; then
NAME=$yesterday
else
NAME=$tomorrow
fi
if [ $tohelp = true ]; then
MSG='runner [-y]'
fi
echo $NAME
echo $MSG
#itachi's answer looks good. Although, if you want to continue using getopts, this should also work:
#! /bin/bash
yesterday="yesterday"
tomorrow="tomorrow"
setday=false
tohelp=false
while getopts "yh" opt
do
case $opt in
y)
setday=true
;;
h)
tohelp=true
;;
esac
done
shift $((OPTIND - 1))
if $tohelp; then
echo "runner [-y]"
exit
elif $setday; then
NAME=$yesterday
else
NAME=$tomorrow
fi
echo $NAME
Output:
$ ./test.sh
tomorrow
$ ./test.sh -y
yesterday
$ ./test.sh -h
runner [-y]

Using getopts in bash to get optional input argument [duplicate]

This question already has answers here:
Optional option argument with getopts
(15 answers)
Closed 8 years ago.
I am using getopts to process the input arguments. I have problem in reading optional argument value.
When I invoke the script with arguments test.sh -t test -r server -p password -v 1
$OPTARG is not returning the value of the optional argument -v.
Can anyone let me know how to process the optional argument value?
#!/bin/bash
usage()
{
cat << EOF
usage: $0 options
OPTIONS:
-h Show this message
-t Test type
-r Server address
-p Server root password
-v Verbose
EOF
}
TEST=
SERVER=
PASSWD=
VERBOSE=
echo "======111======"
while getopts "ht:r:p:v" OPTION
do
case $OPTION in
h)
usage
echo "===Option h selected=="
exit 1
;;
t)
TEST=$OPTARG
echo "====option t selected===$TEST"
;;
r)
SERVER=$OPTARG
echo "=====option r selected==="
;;
p)
PASSWD=$OPTARG
echo "====option p selected==="
;;
v)
VERBOSE=$OPTARG
echo "======option v selected===$VERBOSE"
;;
?)
echo "====unknown option selected===="
usage
exit
;;
esac
done
echo "========222===="
Do the thing in the case statement.
case $OPTION in
v)
VERBOSE=$OPTARG
do_the_thing $OPTARG
;;
esac
Do the thing after the case statement.
if [ ! -z "$VERBOSE" ]; then
do_the_thing "$VERBOSE"
else
do_not_do_the_thing
fi

GETOPTS case with no optional arguments

Hello I'm trying to find a way how to make getopts work with non of expected optional arguments
I have a script with optional arguments
script.sh [-a] [-b] [-c | -d] file
I have it working with -a..-d like this
while geopts abc:abd opt
do
case $opt in
a) do this ;;
b) do this ;;
...
.. etc
I want to make it so it can work without those arguments, so I can run it like this
script.sh file
Is there a way to make a new case option or do I need to do it other way, thanks for all help, im a beginner in bash.
I've done this kind of thing before:
declare -A have=([a]=false [b]=false [c]=false [d]=false)
while geopts :abcd opt; do
case $opt in
a) have[a]=true ;;
b) have[b]=true ;;
c) have[c]=true ;;
d) have[d]=true ;;
?) echo "illegal option: -$OPTARG"; exit 1;;
esac
done
shift $((OPTIND-1))
if ${have[c]} && ${have[d]}; then
echo "cannot give both -c and -d"
exit 1
fi
${have[a]} && do_a_stuff
${have[b]} && do_b_stuff
...
That case statement is a pretty egregious bit of cut'n'paste programming: tightening it up:
while geopts :abcd opt; do
case $opt in
a|b|c|d) have[$opt]=true ;;
?) echo "illegal option: -$OPTARG"; exit 1;;
esac
done
I have the following test script:
#! /bin/bash
USAGE="test.sh [-a] [-b] [-c | -d ]"
while getopts :abcd option
do
case $option in
a) OPT_A=1;;
b) OPT_B=1;;
c) OPT_C=1;;
d) OPT_D=1;;
*)
echo "$OPTARG is not a valid option."
echo "$USAGE"
exit 2;;
esac
done
shift $((OPTIND-1))
if [[ $OPT_C && $OPT_D ]]
then
echo "That's a no-no using options c and d together"
echo "$USAGE"
exit 2
fi
echo "The following options were set"
[[ $OPT_A ]] && echo " Option A was set"
[[ $OPT_B ]] && echo " Option B was set"
[[ $OPT_C ]] && echo " Option C was set"
[[ $OPT_D ]] && echo " Option D was set"
echo "And the file name is $1"
It will show you what options were set (and which ones weren't). It tests to make sure that -c and -d aren't used together.
Not 100% sure what you're asking for. But, you can see that instead of saying do this in my case statement, I'm merely setting variables that show what options were or weren't selected. That in itself my solve your problem.

Resources