Bash script and getopts outputting saved variables - bash

I'm trying to put together a script to monitor files and im having a hard tiem with getopts. If I run more than once the shell values dont changes... There's a ton of clean up but I've been stuck on this one issue for a couple hours so ...
#!/bin/bash
function printUsage {
echo "Usage: $0 [-e environment] [-r region] [-l logtype]"
echo "Requirements:"
echo " -e environment to look in; prod or dev"
echo " -r 3 digit region designation"
echo " -l log type to find; soap, message, main, service, or detail"
echo " example: $0 -e dev -r 111 -f soap"
exit 0
}
if [ $# -lt 1 ]; then
printUsage
fi
while getopts "e:r:l:" opt; do
case $opt in
e)
environment="$OPTARG"
;;
r)
region="$OPTARG"
;;
l)
logtype="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG"
printUsage;;
:)
echo "-$OPTARG requires an argument"
printUsage;;
esac
done
#build array of directories to search based on argument
function buildProductionArray {
# assume these are here
logpaths=( )
}
#build array of directories to search based on argument
function buildDevArray {
# assume these are here
logpaths=( )
}
function validateArguments {
#validate the environment
if [ "$(echo "$environment" | tr "[:lower:]" "[:upper:]")" == "PROD" ]; then
buildProductionArray
elif [ "$(echo "$environment" | tr "[:lower:]" "[:upper:]")" == "DEV" ]; then
buildDevArray
else
echo "Usage: findlog [-e environment] [-r region] [-l logtype]"
echo "Invalid environment" >&2; exit 1
fi
#validate the region
if ! [ "$region" -eq "$region" ] 2>/dev/null; then
echo "Usage: findlog [-e environment] [-r region] [-l logtype]"
echo "Invalid region" >&2; exit 1
fi
#validate the logtype
function in_array() {
elements=${1}
element=${2}
for i in "${elements[#]}" ; do
if [ "$i" == "$element" ] ; then
return 1
fi
done
return 0
}
logvalues=(soap message service main detail)
log="$(echo "$logtype" | tr '[:upper:]' '[:lower:]')"
echo "$log"
if in_array logvalues "${log}"; then
if [[ "$log" == "service" || "$log" == "detail" ]]; then
log="-$log-time-"
else
log="-$log-"
fi
else
echo "Usage: findlog [-e environment] [-r region] [-l logtype]"
echo "Invalid environment" >&2; exit 1
fi
}
validateArguments
for i in "${logpaths[#]}"
do
#assume this is here
done

Related

**UPDATE Issues with .SH file running Correctly

I am trying to use this script to be able to shut down my ESXi server based on network connectivity. I found this script online, on the vmcommunity and no one seems to be having the same issues that I am. When I run this script It returns syntax error: unexpected word (expecting "in"). However the in is there
allInterfaces=$(esxcfg-nics -l | grep vmnic | awk '{print $1}' | awk '$1=$1' OFS=" " RS=)
while [ $# -gt 0 ];
do
case "$1" in
-v) verbose=1;;
-t) downCycles=$2; shift;;
-i) shift; break;;
--) shift; break;;
-*) errorLog "wrong parameter:" "$#" ;;
*) break;;
esac
done
shift
Any advice would be extremely helpful. Below if the full script that I am trying to use.
#!/bin/bash
verbose=0
downCycles=3
stateCounter="/tmp/auto-shutdown.counter"
log() {
logger "auto-shutdown: $1"
if [ $verbose -gt 0 ]; then
echo "$1"
fi
}
errorLog() {
logger "auto-shutdown error: $1"
echo -e >&2 "\n$1\n"
echo -e >&2 "auto-shutdown.sh: shutdown vmware ESXi if network interfaces are down for a number of cycles"
echo -e >&2 "-------------------------------------------------------------------------------------------------"
echo -e >&2 "usage: $0 [-v] [-t cycles] [-i vmnic# vmnic# ...]\n"
echo -e >&2 " -v: verbose\n"
echo -e >&2 " vmnic#: selected vmnic interfaces to monitor"
echo -e >&2 " defaults to all available interfaces\n"
echo -e >&2 " cycles: the down condition is reached, if all selected vmnic interfaces"
echo -e >&2 " have been down for <cycles> consecutive executions of this script\n"
echo -e >&2 "(c) 2011-10-22 by Ralf Lueders, support#lrconsult.com"
echo -e >&2 "-------------------------------------------------------------------------------------------------\n"
exit 1
}
if [ ! -e $stateCounter ]; then
echo 0 > $stateCounter
fi
allInterfaces=$(esxcfg-nics -l | grep vmnic | awk '{print $1}' | awk '$1=$1' OFS=" " RS=)
while [ $# -gt 0 ];
do
case "$1" in
-v) verbose=1;;
-t) downCycles=$2; shift;;
-i) shift; break;;
--) shift; break;;
-*) errorLog "wrong parameter:" "$#" ;;
*) break;;
esac
done
shift
selectedInterfaces=$*
nosi=0
for interface in $selectedInterfaces; do
if [ "$(expr "$allInterfaces" : ".*$interface.*")" -eq 0 ]; then
errorLog "$0 error: interface $interface does not exist"
fi
nosi=$( $nosi + 1 )
done
if [ ${#selectedInterfaces} -eq 0 ]; then
selectedInterfaces=$allInterfaces
fi
if [ $verbose -gt 0 ]; then
echo "monitoring interface(s) $selectedInterfaces ..."
fi
downState=1
for interface in $selectedInterfaces; do
state=$(esxcfg-nics -l | grep "$interface" | awk '{print tolower($4)}')
if [ "$state" = "up" ]; then
downState=0
fi
done
count=$(cat $stateCounter)
if [ "$count" -eq "$downCycles" ]; then
log "initiating system shutdown..."
echo 0 > $stateCounter
/sbin/shutdown.sh
/sbin/poweroff
else
if [ $downState -eq 1 ]; then
count=$( $count + 1 )
countDown=$( "$downCycles - $count" )
log "the interface(s) $selectedInterfaces have now been down for $count cycles, $countDown cycles left before system shutdown."
else
count=0
fi
fi
echo $count > $stateCounter
I have used Charles' suggestions and I am no longer getting errors in ShellCheck. However I am still getting the same error I encountered before where it say that I am missing an in that is clearly there. Anyone see anything else that could be edited to solve this issue. I am really not familiar with shell scripting at all, so any information would be helpful.

How to bypass an optional argument for the following argument in bash?

TABLE=`echo "${1}" | tr '[:upper:]' '[:lower:]'`
if [ $1 = -d ]
then TABLE=daminundation
elif [ $1 = -b ]
then TABLE=burnscararea
elif [ $1 = -r ]
then TABLE=riverpointinundation
elif [ $1 = " " ]
then echo "User must input -d (daminundation), -b (burnscararea)
or -r (riverpointinundation)."
fi
SHAPEFILEPATH=${2}
MERGEDFILENAME=${3}
if [ -z $3 ] ;
then MERGEDFILENAME=merged.shp
else
MERGEDFILENAME=${3}
fi
COLUMNNAME=${4}
if [ -n $4 ]
then COLUMNNAME=$4
fi
$3 & $4 are optional arguments. However, if I choose not to use $3 but I want to use $4, it will read the command as $3. Confused by other methods, how should I make it so that an undesired optional command can be bypassed for the next one?
You probably want this:
#!/bin/bash
while getopts ":b :d :r" opt; do
case $opt in
b)
TABLE=burnscararea
;;
d)
TABLE=daminundation
;;
r)
TABLE=riverpointinundation
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
esac
done
shift $((OPTIND-1))
[ -z "$TABLE" ] && ( echo "At least one of -b/-d/-r options must be provided"; exit 1; )
[ $# -ne 3 ] && ( echo "3 params expected!"; exit 1; )
SHAPEFILEPATH="$2"
MERGEDFILENAME="$3"
COLUMNNAME="$4"
# other stuff

getopts second flag is not required?

Having issues making sure that both -v and -o are both required elements but -h is not in my getopts. how would I fix this?
usage() { echo "Usage: $0 [-v <5.x|6.x>] [-o <string>]" 1>&2; exit 1; }
if ( ! getopts ":v:o:h" opt); then
echo "Usage: `basename $0` options (-v [version]) (-o [organization unit]) -h for help";
exit $E_OPTERROR;
fi
while getopts ":v:o:h" opt; do
case $opt in
v) vermajor=$OPTARG;;
o) org_unit=$OPTARG;;
h) usage;;
\?) echo "Invalid option: -$OPTARG" >&2; exit 1;;
:) echo "Option -$OPTARG requires an argument." >&2; exit 1;;
esac
done
exit
What about this?:
usage() { echo "Usage: $0 [-v <5.x|6.x>] [-o <string>]" 1>&2; exit 1; }
test=$(echo "$#" | grep "\-v" | grep "\-o")
if [[ -z "$test" ]]; then
printf "requirements not met.\n"
usage
fi
if [[ -n "$test" ]]; then
printf "requirements met.\n"
fi
Output:
bob#crunchbang:~$ ./test -v 5.0 -h
requirements not met.
Usage: ./test [-v <5.x|6.x>] [-o <string>]
bob#crunchbang:~$ ./test -v 5.0
requirements not met.
Usage: ./test [-v <5.x|6.x>] [-o <string>]
bob#crunchbang:~$ ./test -o "yoh"
requirements not met.
Usage: ./test [-v <5.x|6.x>] [-o <string>]
bob#crunchbang:~$ ./test
requirements not met.
Usage: ./test [-v <5.x|6.x>] [-o <string>]
Ended up with this
usage() { echo "Usage: $0 [-v <5.x|6.x>] [-o <string>]" 1>&2; exit 1; }
if [[ "$1" =~ "^((-{1,2})([Hh]$|[Hh][Ee][Ll][Pp])|)$" ]]; then
usage
else
while [[ $# -gt 0 ]]; do
opt="$1"; shift
current_arg="$1"
if [[ "$current_arg" =~ ^-{1,2}.* ]]; then
echo "==> WARNING: You may have left an argument blank. Double check your command."
fi
case "$opt" in
"-v"|"--version" ) vermajor="$1"; shift;;
"-o"|"--org" ) org_unit="$1"; shift;;
* ) echo "==> ERROR: Invalid option: \""$opt"\"" >&2
exit 1;;
esac
done
fi
if [[ "$vermajor" == "" || "$org_unit" == "" ]]; then
echo "ERROR: Options -v and -o require arguments." >&2; exit 1
fi
exit

How to use getopts in bash to parse script arguments?

I have seen many examples for how to use getopts. But I know very basic of bash and I was not able to to implement it in my situation. I really appreciated if anyone expert can show me the template.
I have a script with minimum 6 and maximum 10 input. Here is a brief description:
script.sh -P passDir -S shadowDir -G groupDir -p password -s shadow
User must provide argument for -P -S -G and if not I must display usage and close the program. If argument are provided I need them to be saved into an appropriate variable.
But -p and -s is optional. However, if there is no -p I should do some tasks and if there is no -s I should do some other tasks and if none of them is there I should do some other tasks.
Following is what I have written so far but it stock in the for loop.
#!/bin/bash
if [ "$(id -u)" != "0" ]; then
echo "Only root may add a user to system"
exit 2
else
usage() { echo "Usage: $0 [-P <password file path>] [-S <shadow file path>] [-G <group path>]" 1>&2; exit 1; }
passDir=""
shadowDir=""
groupDir=""
while getopts ":P:S:G:" inp; do
case "${inp}" in
P)
$passDir = ${OPTARG};;
S)
$shadowDir = ${OPTARG};;
G)
$groupDir = ${OPTARG};;
*)
usage;;
esac
done
echo "${passDir}"
echo "${shadowDir}"
echo "g = ${groupDir}"
fi
At the moment is user does not enter arguments nothing will be shown and if there is arguments it goes inside a loop!
As I understand it, you are just missing some if statements to handle missing arguments. Consider:
usage() { echo "Usage: $0 [-P <password file path>] [-S <shadow file path>] [-G <group path>]" 1>&2; exit 1; }
if [ "$(id -u)" != "0" ]; then
echo "Only root may add a user to system"
exit 2
fi
passDir=""
shadowDir=""
groupDir=""
while getopts "P:S:G:" inp; do_
case "${inp}" in
P)
passDir=${OPTARG};;
S)
shadowDir=${OPTARG};;
G)
groupDir=${OPTARG};;
*)
usage;;
esac
done
if [ -z "$passDir" ] && [ -z "$shadowDir" ]
then
# if none of them is there I should do some other tasks
echo do some other tasks
elif ! [ "$passDir" ]
then
# if there is no -p I should do some tasks_
echo do some tasks
elif ! [ "$shadowDir" ]
then
#if there is no -s I should do some other tasks
echo do some other tasks
fi
I fixed a couple of things in your script. This works for me:
#!/bin/bash
if [ "$(id -u)" != "0" ]; then
echo "Only root may add a user to system"
exit 2
fi
usage() { echo "Usage: $0 [-P <password file path>] [-S <shadow file path>] [-G <group path>]" 1>&2
exit 1
}
passDir=""
shadowDir=""
groupDir=""
while getopts ":P:S:G:" inp; do
case "${inp}" in
P)
passDir=${OPTARG};;
S)
shadowDir=${OPTARG};;
G)
groupDir=${OPTARG};;
*)
usage;;
esac
done
echo "p = $passDir"
echo "s = $shadowDir"
echo "g = $groupDir"
Assignments must not contain spaces: a=1 works, a = 1 doesn't
The variable name should not be prefixed with a $ in an assignment
If your if branch contains an exit statement, there's no need to put the rest of your code in the else branch

Echo Usage if they don't put parameters correct

I have this
USAGE="Usage: -f [file name] -c [column] -v [value] ."
while getopts ":f:c:v: " OPTIONS; do
case $OPTIONS in
f ) file=$OPTARG;;
c ) column=$OPTARG;;
v ) value=$OPTARG;;
h ) echo $USAGE;;
\? ) echo $USAGE
exit 1;;
* ) echo $USAGE
exit 1;;
esac
done
the filename is fun2.sh ... I want to echo the $USAGE if they fail to put a parameter in -f or -c or -v.
I have tryied putting a
" ") echo $USAGE
exit1;;
but that didn't work..
I also tried
if [ $file || $column || $value == "" ]
echo $USAGE
but then again it didn't work..
Any Help would be appreciated
EDIT
What worked for me
if [ "$file" == "" ] ;
then
echo $USAGE
elif [ "$column" == "" ];
then
echo $USAGE
elif [ "$value" == "" ];
then
echo $USAGE
else
show_column
check_temp
file_move
write_file
Try:
[[ -z "$file" || -z "$column" || -z "$value" ]] && echo "$USAGE" && exit
You can't do this in the loop. Check the values of the variables after the loop and print $USAGE if they are empty or the values are wrong (not an integer, for example).
Not entirely sure why your code doesn't work, but this should:
USAGE="Usage: -f [file name] -c [column] -v [value] ."
params="$(getopt -o f:c:v:h --name "$(basename -- "$0")" -- "$#")"
if [ $? -ne 0 ]
then
echo "$USAGE"
exit 1
fi
eval set -- "$params"
while true
do
case $1 in
-f)
file="$2"
shift 2
;;
-c)
column="$2"
shift 2
;;
-v)
value="$2"
shift 2
;;
-h)
echo "$USAGE"
exit
;;
--)
shift
break
;;
*)
echo "$USAGE"
exit 1
;;
esac
done
John, i dont understand what is a bad with your code: In my bash got the following: (the name of script is "go") - OK mean, got what i expected.
jonatan:shell clt$ ./go
#ok
jonatan:shell clt$ ./go ewdwedw
#ok
jonatan:shell clt$ ./go -a
Usage: -f [file name] -c [column] -v [value] .
#ok, -a is incorrect
jonatan:shell clt$ ./go -f
Usage: -f [file name] -c [column] -v [value] .
#ok, -f need an argument
jonatan:shell clt$ ./go -f aaa
#ok, -f has an argiment
jonatan:shell clt$ ./go -c
Usage: -f [file name] -c [column] -v [value] .
jonatan:shell clt$ ./go -c -v
#hm - "-v" comes into `column`, so syntactically is ok, but ....
Therefore you need another check - as you done already. So, your script is OK.
Here is my "go".
#!/bin/bash
USAGE="Usage: -f [file name] -c [column] -v [value] ."
while getopts ":f:c:v:" OPTIONS; do
case "$OPTIONS" in
f ) file=$OPTARG;;
c ) column=$OPTARG;;
v ) value=$OPTARG;;
h ) echo $USAGE;;
\? ) echo $USAGE; exit 1;;
* ) echo $USAGE; exit 1;;
esac
done

Resources