Bash script ends without doing echo - bash

I am running a script from command line that runs a bunch of Jmeter tests if 4 variables are set.
The script works but I have added parts so the script will end if the server is unknown.
if [ echo "$2" != | grep -iq "^hibagon" ] || [ echo "$2" != | grep -iq "^kameosa" ] ;then
echo "Unkown server stopping tests"
else
echo "Continueing to tests"
when this section of the script runs it will end the script if hibagon or kameosa is not found (not case sensitive).
I want the command line to echo Unknown server stopping tests then end but at the moment it just ends with no echo

That's a strange syntax. Try this:
if echo "$2" | grep -iq "^hibagon\|^kameosa";
then
echo "Continuing to tests"
else
echo "Unkown server, stopping tests"
fi
Or if you're using bash:
if [[ "$2" =~ ^hibagon ]] || [[ "$2" =~ ^kameosa ]]
then
echo "Continuing to tests"
else
echo "Unkown server, stopping tests"
fi

First the test [ echo "$2" != | grep -iq "^hibagon" ] is wrong, then you can use only one (extended)grep with the negation flag -v putting together the two words in one regex ^(hibagon|kameosa). Also the fi was missing. but I suppose it's only a typo here.
if echo "$2" | egrep -ivq "^(hibagon|kameosa)"; then
echo "Unknown server stopping tests"
else
echo "Continuing to tests"
fi
If you like it, even:
if egrep -ivq "^(hibagon|kameosa)" <<< "$2"; then

Related

Perform action if nothing is returned

I'm trying to echo "It was not found" if the netstat returns no result. But, if it does return a result, then to display the netstat results.
I'm trying to google for what I'm using and can't find much about it.
#!/bin/bash
echo "Which process would you like to run netstat against?"
read psname
echo "Looking for '$psname'"
sleep 2
command=$(netstat -tulpn | grep -e $psname)
[[ ! -z $command ]]
It's to do with the [[ ! -z $command ]]
[[ ! -z $command ]] doesn't 'show' you any output.
Use a if/else setup to show the result;
if [[ ! -z $command ]]; then
echo "$psname was found!"
else
echo "No process named '${psname}' found!"
fi
Or a shorthand variant;
[[ ! -z $command ]] && echo "$psname was found!" || echo "No process named '${psname}' found!"
Note if the user input may contain a space, it's saver to use "" around the grep string;
command=$(netstat -tulpn | grep -e "$psname")
When to wrap quotes around a shell variable?
Do not intercept the output directly. You can instead do something like:
if ! netstat -tulpn | grep -e "$psname"; then
echo "not found" >&2
fi
If grep matches any output, it will print it to stdout. If it mathches nothing, it returns non-zero and the shell will write a message to stderr.

raise error if files output some error (without raising shell error)

I want to do raise an error if an executable outputs something specific...(like "error"):
echo "abcdef" | [[ "$(grep "f")" != "" ]] && echo "error"
"error"
echo "abcdef" | [[ "$(grep "g")" != "" ]] && echo "error"
""
This work but when applying it to an exe it fails
test_if_exe_fails(){
$1 | [[ "$(grep "$2")" != "" ]] && echo "error: $2" && exit 1
}
when running myApp.exe | test_if_exe_fails "myerror message" it exits
line xxx: myerror : command not found
so I tried using this method but still doesn't work
let's say the output of my exe start with "BLA BLA FOO", if I do:
test_if_exe_fails "$(myApp.exe)" "myerror message"
it gives :
line xxx: BLA : command not found
more examples:
1/
test_if_exe_fails "$(echo 'hello')" "hola"
line xx: hello: command not found
2/
test_if_exe_fails "$(echo 'hello')" "hello"
line xx: hello: command not found
The purpose of [[ ... ]] is to generate an exit code that if, &&, or || can test. grep already does that. You don't care about grep's output, and you can suppress it with the -q option.
echo "abcdef" | grep -q "f" && echo "error"
Note that your function is wrapping the pipeline, but you have removed the echo command. You need to put that back. (Actually, you should use printf instead of echo for portability and predictability. And finally, error messages should be written to standard error, not standard output.
test_if_exe_fails(){
print '%s' "$1" | grep -q "$2" && echo "error: $2" >&2 && exit 1
}
test_if_exe_fails "$(myApp.exe)" "myerror message"
One last improvement: rather than capture the output of myApp.exe, just pipe it directly to the function:
test_if_exe_fails(){
grep -q "$1" && echo "error: $1" >&2 && exit 1
}
myApp.exe | test_if_exe_fails "myerror message"
So your function
test_if_exe_fails(){
$1 | [[ "$(grep "$2")" != "" ]] && echo "error: $2" && exit 1
}
Says "Run the program $1 and grep the output for $2"
That means that when you call this function you should supply the NAME of the program you want to run.
But that is silly. In the examples with echo you want arguments, so you can't do that like that. There are a number of ways to solve this, but they all involve the function NOT RUNNING THE PROGRAM AGAIN!

Setting a variable inside a conditional

Is it possible to set a variable from the output of a command inside of a conditional where the conditional is false if nothing gets assigned to the variable.
If I set the variable to a grep with no return and then test:
test=$(echo hello | grep 'helo')
if [[ ! -z $test ]]; then
echo "is set"
else
echo "not set"
fi
Output: not set (this is expected)
But I'm trying to put it all into one statement like this:
test=
if [[ ! -z test=$(echo hello | grep 'helo') ]]; then
echo "is set"
else
echo "not set"
fi
output: "is set" (expected not set)
grep returns success if there is a match, so you can just do:
if test=$(echo hello | grep 'helo')
then
echo "Match: $test"
else
echo "No match"
fi
If you're running something that doesn't differentiate by exit code, you can assign and check in two statements on the same line:
if var=$(cat) && [[ -n $var ]]
then
echo "You successfully piped in some data."
else
echo "Error or eof without data on stdin."
fi
(or ; instead of && if you want to inspect the result even when the command reports failure)
Bit of a hack, using the shell's parameter expansion alternate value syntax, echo -e and some backspaces:
test=$(echo hello | grep 'helo'); echo -e not${test:+\\b\\b\\bis} set
Which outputs is set or not set depending on what grep finds.

getops still performs default actions when arguments are provided

I've recently started working with the getopts command in bash. I am confused as to why my script runs the dafult action "cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl" when arguments have been provided. I only want that to run if no arguments were passed to the shell script. I've used getopts:Std in perl where I was able to code somthing like:
unless ($opts{d}) {
do something...}
How would I code something like that in a shell script? Also, how would I code logic such as this:
if ($opts{c}) {
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -c
}
elsif ($opts{d} {
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -d
My code:
#!/bin/sh
while getopts cd name
do
case $name in
c)copt=1;;
d)dopt=1;;
*)echo "Invalid arg";;
esac
done
if [[ ! -z $copt ]] #Specifies what happens if the -c argument was provided
then
echo "CSV file created!"
cat "~/bin/Temp/log.txt" | ~/bin/Scripts/vpnreport/report.pl -c
fi
if [[ ! -z $dopt ]] #Specifies what happens if the -d argument was provided
then
echo "Debug report and files created"
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -d
fi
if [[ ! -z $name ]] #Specifies what happens if no argument was provided
then
echo "Running standard VPN report"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl
fi
shift $(($OPTIND -1))
My Output:
[~/bin/Scripts/report]$ sh getoptstest.sh
Running standard report
[~/bin/Scripts/report]$ sh getoptstest.sh -d
Debug report and files created
Running standard report
[~/bin/Scripts/report]$
The two getopts commands are vasty different from bash to perl and I just can't seem to get the hang of the bash varient even after reading several tutorials. Any help would be greatly appreciated!
On the final run of getopts, your variable (name) will be set to "?".
#!/bin/bash
while getopts abc foo; do :; done
echo "<$foo>"
Output of the above:
$ ./mytest.sh
<?>
$ ./mytest.sh -a
<?>
Insead, use elif, which is like Perl's elsif:
if [[ ! -z $copt ]]
then
# ...
elif [[ ! -z $dopt ]]
then
# ...
else
# ...
fi
Or test if [[ -z $copt && -z $dopt ]], or so forth. Other notes:
See the official if and case documentation in the Bash manual under "Conditional Constructs".
[[ ! -z $name ]] means the same as the more-direct [[ -n $name ]].
Use #!/bin/bash instead of #!/bin/sh, or switch off of [[ in favor of [. The double square bracket (and your use thereof) is specific to bash, and rarely works with sh.
I took Jeff's answer and rewrote my script so it works now:
#!/bin/bash
while getopts cd name
do
case $name in
c)carg=1;;
d)darg=1;;
*)echo "Invalid arg";;
esac
done
#Specifies what happens if the -c argument was provided:
if [[ ! -z $carg ]]
then
if [[ -z $darg ]]
then
echo "CSV created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -c
else
echo "Debug CSV created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -cd
fi
fi
#Specifies what happens if the -d argurment was provided:
if [[ ! -z $darg ]]
then
echo "Debug report created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -d
#Specifies what happens if no argument was provided:
else
echo "Standard report created"
cat ~bin/Temp/logs.txt | ~bin/Scripts/report.pl
fi
Thank you again for your assistance!

What is the difference between "else if" and "elif" in bash?

I've got the following shell script that's supposed to simply stage a few Java .ear/.war files to JBoss:
SUCCESS=false
DEPLOY_PATH=/apps/jboss/server/default/deploy
E_NOARGS=75
M_USAGE="usage: $0 {rcm|hcm}"
M_MISSING_RCM="missing: rcm.war file not present"
M_MISSING_HCM="missing: hcm.ear or hcm.war file not present"
if [ -z "$1" ]
then
echo $M_USAGE
exit $E_NOARGS
else
M_START="deploying $1 ..."
M_FINISH="finished deploying $1"
fi
until [ -z "$1" ]
do
echo $M_START
case "$1" in
rcm*)
# do a hot-deploy of the rcm.war file
# TODO: test if rcm.war file is present, error out if not
if [ -e rcm.war ]
then
cp -v rcm.war $DEPLOY_PATH/rcm.war
SUCCESS=true
else
echo $M_MISSING_RCM
fi
;;
hcm*)
# do a shutdown, deploy hcm.war, and restart jboss
ps -ef | awk '/jboss/{print $2}' | xargs kill -s KILL
HCM_DEPLOYED=false
if [ -e hcm.ear ]
then
cp -v hcm.ear $DEPLOY_PATH/hcm.ear
HCM_DEPLOYED=true
else
if [ -e hcm.war ]
then
cp -v hcm.war $DEPLOY_PATH/hcm.war
HCM_DEPLOYED=true
else
echo $M_MISSING_HCM
fi
fi
if $HCM_DEPLOYED ;
then
# TODO: detect the hostname
nohup /apps/jboss/bin/run.sh -b <HOSTNAME> & &> /dev/null
SUCCESS=true
fi
;;
*)
echo $M_USAGE
exit 1
esac
shift
done
if $SUCCESS ;
then
echo $M_FINISH
fi
The section in particular that confuses me is this one:
if [ -e hcm.ear ]
then
cp -v hcm.ear $DEPLOY_PATH/hcm.ear
HCM_DEPLOYED=true
else
if [ -e hcm.war ]
then
cp -v hcm.war $DEPLOY_PATH/hcm.war
HCM_DEPLOYED=true
else
echo $M_MISSING_HCM
fi
fi
I can't seem to get elif [ -e hcm.war ] to work correctly on the remote server. The remote server is running bash 3.2.25 on redhat (if that makes any difference.) I suspect I'm just missing some picky bash shell script detail.
Any suggestions?
Your code as posted seems to work.
There is a difference between elif .. fi AND else ; if ... fi. A true elif ... fi will have one fewer fi at the end than your code.
Your code as posted, asks, "if hcm.ear exists THEN check if there is an hcm.war". Is that what you want? The other logic path to test would be "if hcm.ear doesn't exist THEN check if there an hcm.war."
That alternate logic path looks like
if [ -e hcm.ear ] ; then
cp -v hcm.ear $DEPLOY_PATH/hcm.ear
HCM_DEPLOYED=true
elif [ -e hcm.war ] ; then
cp -v hcm.war $DEPLOY_PATH/hcm.war
HCM_DEPLOYED=true
else
echo $M_MISSING_HCM
fi
I hope this helps.
This isn't a direct answer to the question (elif vs else) but I would refactor like so:
HCM_DEPLOYED=true
cp -v hcm.ear "${DEPLOY_PATH}/" || cp -v hcm.war "${DEPLOY_PATH}/" || HCM_DEPLOYED=false
if [ ! ${HCM_DEPLOYED} ]; then
echo "${M_MISSING_HCM}"
else
# TODO: detect the hostname
...
I.e. always try the copies since you always want to do them, if one fails try the next, etc.
As an aside, you always want to wrap paths and strings in quotes. Otherwise a path containing spaces will cause your app to break.

Resources