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.
Related
I have a simple bash script, see below
#!/bin/bash
while getopts "t" opt; do
case $OPT in
t) JWT_TOKEN="$OPTARG"
;;
\?) echo "Invalid option -$OPTARG" >&2
;;
esac
done
echo "Token value is $JWT_TOKEN"
A simple test call is
my-script.sh -t 'test'
However this creates the following output
sedavidw#MacbookPro~$ sh my-script.sh -t 'test'
Token value is
sedavidw#MacbookPro~$
UPDATE
Was able to fix my script by changing it to
#!/bin/bash
while getopts "t:" opt; do
case "${opt}" in
t) JWT_TOKEN="$OPTARG"
;;
\?) echo "Invalid option -$OPTARG" >&2
;;
esac
done
echo "Token value is $JWT_TOKEN"
From the comments it looks like the t: change was helpful for the argument. But still not clear on the syntax change for the "${opt}" part, and would like some clarity there
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
Like i am passing this argument to command line
trace.sh -f abc -t 20
i want to extrace (-t 20) in a variable. how to do that?
Thanks
Very basic example (not fully error prone)
err() { echo "$#" >&2; return 1; }
declare -A options
options=([f]="abc" [t]="20") #the defaults
while getopts ":f:t:" opt
do
case "$opt" in
f) options[$opt]="$OPTARG" ;;
t) options[$opt]="$OPTARG" ;;
\?) err "Invalid option -$OPTARG" || exit 1 ;;
esac
done
echo "t: ${options[t]}"
echo "f: ${options[f]}"
I have a bash script which takes few command line args and a filename as inline parameter. I am not able to read the inline parameter.
sh test.sh -a a -b b -c c < pwd.txt
test.sh has
if [ $# = 0 ]
then
echo $USAGE >&2
exit $STATUS_ERROR_FAIL
fi
# Parse command line options.
while getopts a:b:c: OPT;
do
case "$OPT" in
a)
a="$OPTARG"
;;
b)
b="$OPTARG"
;;
c)
c="$OPTARG"
;;
\?)
# getopts issues an error message
echo $USAGE
exit $STATUS_ERROR_FAIL
;;
esac
done
shift $((OPTIND-1))
echo "1=$1"
your script is working fine, your error is
echo "1=$1"
if you want to see your parameter you should add an echo/print in your case
#!/bin/bash
if [ $# = 0 ]
then
echo $USAGE >&2
exit $STATUS_ERROR_FAIL
fi
# Parse command line options.
while getopts a:b:c: OPT;
do
case "$OPT" in
a)
a="${OPTARG}"
echo "a[$a]"
;;
b)
b="${OPTARG}"
echo "b[$b]"
;;
c)
c="${OPTARG}"
echo "c[$c]"
;;
\?)
# getopts issues an error message
echo $USAGE
exit $STATUS_ERROR_FAIL
;;
esac
done
shift $((OPTIND-1))
or
you can add the echo/print at the end of the script.. it's depend by your needs
output
[shell] ➤ ./t -a 1 -b 2 -c 3
a[1]
b[2]
c[3]
Regards
Claudio
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
~