how to make sure first command finishes and then only execute second command in shell script - linux

how to make sure first command finishes and then only execute second command in shell script
#!/bin/sh
echo "Stopping application"
#command to stop application
echo "Starting application"
#command to start application
In above code, I wanted to make sure that command to stop application is finished properly and then only start the application.
How to handle this.
Please note in my case if application is already stopped then command to stop application takes some random time to complete i.e. 20sec, 30 sec .
So adding sleep is not proper way.
Main moto behind script is to restart application.
Considering fact that if application is allready stopped it doesnt work properly.
If application is running then the script works perfect.

You can use the command return code and a condition to do this.
#!/bin/sh
echo "Stopping application"
#command to stop application
rc=$?
# if the stop command was executed successfuly
if [ $rc == 0 ]; then
echo "Starting application"
#command to start application
else
echo "ERROR - return code: $rc"
fi

There are 'exit codes', try this:
ls
...
echo $?
0
than:
ls non_existing_file
ls: cannot access 'non_existing_file': No such file or directory
echo $?
2
This command echo $? prints exit code of previous command, if it's 0 than it's OK, all non 0 codes means some kind of error which is not OK.

Related

Run Node Server from CPanel Cron Job

I have a Node.JS server running on PM2 that's crashing every once in a while because of a database limit, which I'm working on.
In the meantime, I thought I'd try just setting up a cron job in cpanel to restart the server every hour if it's down.
So I wrote a bash script like the following:
#!/bin/bash
status_code=$(curl --write-out %{http_code} --silent --output /dev/null https://website.com/)
date >> cronlog.txt
if [[ "$status_code" -ne 200 ]] ; then
pkill node
nohup pm2 start bin/www &
echo "Site status $status_code" >> cronlog.txt
echo "Restarting Server" >> cronlog.txt
exit
else
echo "Site fine" >> cronlog.txt
exit 0
fi
Running this from an SSH terminal works perfectly; if the site is down, it'll restart it.
However, once I set up the cron job in cpanel, like so: 0 * * * * /home/acc123/fix.sh, looking at the output of cronlog.txt, I see that the script is definitely running every hour, trying to restart the server - it's just that the server doesn't restart.
A preliminary Google suggested that maybe pm2 wasn't on the path that the cron job runs from, so I modified the script to look like this:
#!/bin/bash
status_code=$(curl --write-out %{http_code} --silent --output /dev/null https://website.com/)
date >> cronlog.txt
if [[ "$status_code" -ne 200 ]] ; then
pkill node
nohup /home/acc123/bin/pm2 start /home/acc123/bin/www &
echo "Site status $status_code" >> cronlog.txt
echo "Restarting Server" >> cronlog.txt
exit
else
echo "Site fine" >> cronlog.txt
exit 0
fi
But nothing changes. Looking at the text file I write to, the script is definitely running every hour, and it's definitely picking up that the site is down, but while the words "Restarting Server" get written to the text file, the server doesn't actually start.
Checking nohup.out confirms that nothing has been written to it, suggesting that somehow the command nohup /home/acc123/bin/pm2 start /home/acc123/bin/www & isn't running correctly.
I'm stumped. Has anyone seen something similar before?
Found it. Looks like node itself also wasn't on the path variable for the cron job. Explicitly specifying where node was fixed the problem.

Set timeout for shell script, to make it exit(0) when time is over

When I set up a Jenkins job and found a problem about timeout for shell script.
It works like this:
Start Jenkins → control.sh is launched → test1.sh is launched in control.sh
Part code of control.sh is like:
#!/bin/sh
source func.sh
export TIMEOUT=30
# set timeout as 30s for test1.sh
( ( sleep $TIMEOUT && function_Timeout ) & ./test1.sh )
# this line of code is in a = loop actually
# it will launch test2.sh, test3.sh... one by one
# later, I want to set 30s time out for each of them.
function_Timeout() {
if [ ! -f test1_result_file]: then
killall test1.sh
# the test1_result_file will not
# be created if test1.sh is not finished executing.
fi
}
part of func.sh is as below
#!/bin/sh
function trap_fun() {
TRAP_CODE=$?
{ if [ $TRAP_CODE -ne 0 ]; then
echo "test aborted"
else
echo "test completed"
} 2>/dev/null
trap "trap_fun" EXIT
After control.sh is launched by Jenkins job, the whole control.sh will be terminated when time is over, and the line of killall test1.sh is reached, and the Jenkins job stop and fail.
I guess it's because test1.sh is killed and exit code is not 0, so it cause this problem.
So my question is, is there someway to terminate or end the sub-script (launched by the main one, like control.sh in my case) exit with code 0?
Updated on July 1:
Thanks for the answers so far, I tried #Leon's suggestion, but I found the code 124 sent by timeout's kill action, is still caught by the trap code - trap "trap_fun" EXIT, which is in func.sh.
I added more details. I did a lot google job but still not found a proper way to resolve this problem:(
Thanks for your kind help!
Use the timeout utility from coreutils:
#!/bin/sh
timeout 30 ./test1.sh
status=$?
if [ $status -eq 124 ] #timed out
then
exit 0
fi
exit $status
Note that this is slightly different from your version of timeout handling, where all running instances of test1.sh are being terminated if any one of them times out.
I resolved this problem finally, I added the code below in each testX.sh.
trap 'exit 0' SIGTERM SIGHUP
It is to make test1.sh exit normally after it receives killall signal.
Thanks to all the help!

Function in shell script not executed correctly

I write a script to start/stop/restart a custom server application.
When starting the daemon server it should make the following:
#!/bin/sh -e
### BEGIN INIT INFO
...
...
### END INIT INFO
# Start service
pga_server_start()
{
/opt/pga/server/server -d
}
# Stop service
pga_server_stop()
{
PID=`cat /var/lock/pga_server.lock`
/bin/kill --signal SIGTERM $PID
}
pga_load_excalibur()
{
is_loaded=`lsmod | grep excalbr`
echo "Done"
if [ -z "$is_loaded" ]; then
/usr/local/bin/excload
echo "Driver excalibur loaded."
else
echo "Driver excalibur already loaded."
fi
}
case "$1" in
start)
pga_load_excalibur
pga_server_start
;;
...
...
Initialy it worked fine. Then I've added the pga_load_excalibur function.
Afterward, it does not work anymore.
It never returns from the function pga_load_excalibur.
It seems that the call to is_loaded=lsmod | grep excalbrnever returns as the subsequentecho` is never printed.
However, if I copy/paste this function in a separate shell script...it works.
But if I launch the starter script manually this way:
/etc/init.d/server start
or
service server start
it does not work.
I'm using a Debian Wheezy 7.9 x64.
Although I'm not a schell script, it looks correct. I don't understand why it does not work when it's embedded into this service starter script.
Please note that I've also tried to replace the grep line with:
is_loaded=$(lsmod | grep excalbr)
But it does not work either.
I'm running out of ideas :(
Z.
What do you get if you run the script in debug mode? try to run it with:
#!/bin/sh -xv
That may give some idea of why it's failing, post the output if you can't figure it out

bash script flock() locking and starting service

I want to use flock to make sure only once instance of script is running at any given time.
Script skeleton looks like this:
ME=`basename "$0"`;
LOCK="/tmp/${ME}.LCK";
exec 8>$LOCK;
if flock -n -x 8; then
do things
if [ condition ]; then
/path/asterisk_restart.sh
fi
else
echo "$(date) script already running >> $log_file"
fi
Now the script /path/asterisk_restart.sh do many things, but in the end asterisk is stopped and last command is service asterisk start
The problem is this: as file handles and locks are shared across fork()/exec(), 8 filehandle remained locked in asterisk process, so the script will not run again once /path/asterisk_restart.sh is executed (and asterisk are not stopped/restarted by other means outside this script)
So my approach is to start sub-shell and close 8 file handle just before executing /path/asterisk_restart.sh.
It looks like this:
ME=`basename "$0"`;
LOCK="/tmp/${ME}.LCK";
exec 8>$LOCK;
if flock -n -x 8; then
do things
if [ condition ]; then
(
exec 8>&-
/path/asterisk_restart.sh
)
fi
else
echo "$(date) script already running >> $log_file"
fi
Is this a sound approach?
To prevent scripts against parallel run, I would suggest something like this.
if mkdir $LockDir; then
echo "Locking succeeded" >&2
# Your script here.
rm -f $LockDir
else
echo "Lock failed - exit" >&2
exit 1
fi
Using a directory instead of a file is better because mkdir is an atomic operation and hence would eliminate the race condition.
Also don't put your LockDir inside /tmp. If it gets removed, the lock is gone.
The only problem with the above implementation is that it does not work when the LockDir gets removed by some other script.

Adding a service startup script for Amazon linux AMI

I am using an Amazon Linux AMI and doing some custom modifications(added an axis2server, etc) on it and saving it as a new AMI. Now what I want to do is when the AMI boots up, start up axis2server(ie.axis2server should automatically start when the instance boots up). For that I used a init script like below and ran the following command:
chkconfig --add axisservice
But when I launch a new instance from my image, the axis2server is not getting started.
I just only need to execute the script /home/ec2-user/axis2-1.6.1/bin/axis2server.sh at startup. Am I missing anything here?
#! /bin/sh
# Basic support for IRIX style chkconfig
###
# chkconfig: 235 98 55
# description: Manages the services you are controlling with the chkconfig command
###
case "$1" in
start)
echo -n "Starting axisservice"
touch ~/temp.txt
cd /home/ec2-user/axis2-1.6.1/bin
./axis2server.sh &
echo "."
;;
stop)
echo -n "Stopping axisservice"
echo "."
;;
*)
echo "Usage: /sbin/service axisservice {start|stop}"
exit 1
esac
exit 0
I went through https://help.ubuntu.com/community/CloudInit as well and it provides a mechanism called User-Data Scripts, where a user can execute a script when launching the script.
$ euca-run-instances --key mykey --user-data-file myscript.sh ami-axxxx
This is a command line option and what I want is something like when I launch the instance through the UI, the script should be started.Therefore, I think the above option can not be used in my case. Please correct me if I am wrong.
Thanks,
H.
I bet the environment is not set(up correctly). This means that I am guessing that your shell script tries to start another program and it's not to be found.
So at first, I'd adjust the start part of your script (current):
echo -n "Starting axisservice"
touch ~/temp.txt
cd /home/ec2-user/axis2-1.6.1/bin
./axis2server.sh &
echo "."
Edited:
echo -n "Starting axisservice"
touch ~/temp.txt
cd /home/ec2-user/axis2-1.6.1/bin
./axis2server.sh
RETVAL=$?
[ $RETVAL -eq 0 ] && echo Success
[ $RETVAL -ne 0 ] && echo Failure
echo "."
So what did I do?
removed & so script waits for your shell script (axis2server.sh) to complete
checked the return status ($?) of your shell script
Further debugging:
Add set -x to your scripts to enable tracing and log both stderr and stdout.
Questions:
Are you are aware that stop (in your service script) doesn't do anything?
touch ~/temp.txt is that supposed to create /root/temp.txt? (I'm guessing root runs this script.)
If none of my suggestions work, can you share axis2server.sh and paste stderr and stdout?

Resources