Parse output of a command in shell script - linux

I am running supervisord service on my server to run two binaries. From a shell script I am updating the RPMs for the two. When I update them, I want to check if they are running or not. If yes, then it gives a stop command to stop the binaries. If not, then the error message should not be printed. Here is my sample output and script:
root>test-rc-002#/home/lab>supervisorctl status all
Binary1 RUNNING pid 5444, uptime 0:04:12
Binary2 RUNNING pid 5445, uptime 0:04:12
root>test-rc-002#/home/lab>service supervisord stop
Stopping supervisord (via systemctl): [ OK ]
root>test-rc-002#/home/lab>supervisorctl status all
http://localhost:9001 refused connection
Here is part of script:
supervisorctl stop Binary1
supervisorctl stop Binary2
service supervisord stop
PID=`ps -eaf | grep /opt/abcd/binary1/binary1 | grep -v grep | awk '{print $2}'`
if [[ "" != "$PID" ]]; then
echo "killing $PID"
kill -9 $PID
fi
What I want to do is:
1) Check the status through - supervisorctl status all
Binary1 RUNNING pid 5444, uptime 0:04:12
Binary2 RUNNING pid 5445, uptime 0:04:12
2) If they are running, then only pass commands -
supervisorctl stop Binary1
supervisorctl stop Binary2
service supervisord stop
3) If they are not running, then "refused connection" will come somewhere in the message, take it and then move to the PID killing part. The message should not be printed on terminal.
I am new to shell scripting and not able to parse the output. Please help.

For parsing the lines in the file you can pass each line to another function which will receive the lines as $1 $2 etc. For example:
sub()
{ if [ $2 = "RUNNING" ]; then
echo RUNNING
else
echo "not running"
fi
}
sub asdf RUNNING asfasf
sub asdfa asdfasdf asfdasd

Related

Bash - use 1 stop script for multiple similar services, and kill the correct process only

I have multiple processes running as services on a machine
Before moving from 1 process/service to multiple ones, I used the following script to stop my service
#!/bin/sh
SIGNAL=${SIGNAL:-TERM}
PIDS=$(ps ax | grep -i 'datastream' | grep java | grep -v grep | awk '{print $1}')
if [ -z "$PIDS" ]; then
echo "No Brooklin server to stop"
exit 1
else
kill -s $SIGNAL $PIDS
fi
The issue now is that this script kills all processes of this type if invoked as a service stop command
My services are called for example service-A, service-B, service-C. If I send a service service-C stop command, the current script will stop all 3 processes.
I would like to make the script use the provided service name to determine which process to stop (I can grep A/B/C from the process output to ps, but I haven't managed to tell it how to stop only the process given in the service stop command.
Does anyone have experience handling something similar?
You can try something like below while starting your application which can store your PID in a static file and then you can use the same file to kill the process.
Pasting below one of my start - stop script which I have used in past for churning up multiple processes.
Start Script :-
#!/bin/bash
export PORT=$1
. /application/setEnv.sh
/java/jdk1.8.0_152/bin/java -Xms512m -Xmx2G -XX:+DisableExplicitGC -jar /application/api-1.0-0-all.jar </dev/null >>$LOGDIR/service$PORT.log 2>&1 &
echo $! > /application/service$PORT.pid
disown $!
Stop Script :-
#!/bin/bash
PORT=$1
PID=`cat /application/service$PORT.pid`
if [ ! -z "$PID" ]; then
rm /application/service$PORT.pid
kill -9 $PID >/dev/null 2>&1
if [ $? -gt 0 ]; then
echo "PID file found but no matching process was found. Stop aborted."
exit 1
fi
else
echo "PID file is empty and has been ignored."
fi
mv /application/logs/service$PORT.log /application/logs/service$PORT.log`date +%d%m%Y%H%M%S`
Only change which I can think of is the replace my port utilisation logic viz. $PORT with your service names viz. A/B/C.

I want to output "<PID> Killed ~" to logfile when it kill -9 <PID>

I want to output this message /usr/local/ex1.sh: line xxx: <PID> Killed ex2.sh >> $LOG_FILE 2>&1 to logfile.
however
The "ex1.sh" output /usr/local/ex1.sh: line xxx: <PID> Killed ex2.sh >> $LOG_FILE 2>&1 to console when I executed ex1.sh in console.
The result that i want is that "ex1.sh" output to file, not that output to console.
This source is "ex1.sh".
ex2.sh >> $LOG_FILE 2>&1 &
PID=`ps -ef | grep ex2.sh | grep -v grep | gawk '{print $2}'`
/bin/kill -9 $PID >> $LOG_FILE 2>&1 &
Why does "ex1.sh" output this message to console?
The reason is that message '/usr/local/ex1.sh: line xxx: <PID> Killed ex2.sh >> $LOG_FILE 2>&1 is given by bash shell, not by kill command.
So if you redirect kill command output to a file, you will not get the message in the file.
If running like ./ex1.sh >> $LOG_FILE 2&>1, the message will be in the log file. Because ./ex1.sh forks a new bash process, the bash process will give out the message.
The output is in fact not written by the kill command or ex2.sh. It is written by the shell executing the background process ex2.sh.
The shell executing the script started the script ex2.sh in the background as a child process and is monitoring it. When the script is killed, the shell acts on this by printing the message.
In your special case the shell knows more about the killed process and the process executing kill. So it prints a rather verbose message.
If you start ex2.sh (without '&') in terminal 1 and kill it from terminal 2, the shell in terminal 1 will just print "Killed".

Checking if a node.js app has started properly using bash

I wrote a node.js application and have written a bash script to start it and verify if it's running. I have my script run npm start & first, then I have a check to see if the ports I want open are open using netstat. The check works fine when I run it after the script is run, but during the running of the script, the check fails because the server has not fully started before the check is run. My code is below:
echo "Starting the server..."
npm start & > /dev/null 2>&1
if [[ -z $(sudo netstat -tulpn | grep :$portNum | grep node) ]] ; then
echo -e "\tPort $portNum is not in use, something went wrong. Exiting."
else
echo -e "\tPort $portNum is in use!"
fi
Is there a good way to take the above script and change it so that the check doesn't occur until the server is fully started? I don't want to use sleep if I can help it.
You can use a wait call:
echo "Starting the server..."
npm start & > /dev/null 2>&1
wait
if [[ -z $(sudo netstat -tulpn | grep :$portNum | grep node) ]] ; then
echo -e "\tPort $portNum is not in use, something went wrong. Exiting."
else
echo -e "\tPort $portNum is in use!"
fi
The only limitation to this is that if npm daemonizes itself then it's no longer a child of the script so the wait command will have no effect (the reason for this is that a process daemonizes itself by terminating and spawning a new process that inherits its role).

How to get the status of any service in a sh script on centos 7?

I am trying to get the service status (for a /bin/sh script) and start it if is not running.
I found some scripts, but does not work for centos 7.
There are, as usual, multiples ways to do this. Just one example, that check if postfix is running:
#!/bin/sh
PID=`cat /var/spool/postfix/pid/master.pid`
# echo $PID
PS=`/bin/ps axu | grep $PID | grep -v grep`
# echo $PS
if [ "$PS" = "" ]
then
/sbin/service postfix restart
fi
You could use "pid" file, or try to detect if process is running (parsing output of "ps axu |grep process_name"), or parse output of "service process status" command, etc, etc.

Start and stop openconnect using Bash

I am trying to achieve the following:
./vpnconnect.sh start should establish a VPN connection to a server.
./vpnconnect.sh stop should terminate the VPN connection.
Here is the attempted shell script which doesn't work as expected.
It gives error:
~$ ./vpnconnect.sh stop
Stopping VPN connection:
./vpnconnect.sh: 22: ./vpnconnect.sh: root: not found
./vpnconnect.sh: 26: ./vpnconnect.sh: 14128: not found
The script:
#!/bin/sh
#
#
#
#
PIDOCN=""
VAR2=""
# Start the VPN
start() {
echo "Starting VPN Connection"
eval $(echo 'TestVpn&!' | sudo openconnect -q -b --no-cert-check 127.0.0.1 -u myUser --passwd-on-stdin)
success $"VPN Connection established"
}
# Stop the VPN
stop() {
echo "Stopping VPN connection:"
VAR2=eval $(sudo ps -aef | grep openconnect)
echo $VAR2
eval $(sudo kill -9 $VAR2)
PIDOCN=eval $(pidof openconnect)
echo $PIDOCN
eval $(sudo kill -9 $PIDOCN)
}
### main logic ###
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status openconnect
;;
restart|reload|condrestart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status}"
exit 1
esac
exit 0
The error messages:
./vpnconnect.sh: 22: ./vpnconnect.sh: root: not found
./vpnconnect.sh: 26: ./vpnconnect.sh: 14128: not found
Come from these lines:
VAR2=eval $(sudo ps -aef | grep openconnect)
PIDOCN=eval $(pidof openconnect)
These lines are non-sense. The shell takes the output of the $(...) sub-shells and tries to execute them as commands, with VAR2 and PIDOCN variables set to "eval". This is definitely not what you wanted.
Probably you're looking for something more like this:
stop() {
echo "Stopping VPN connection:"
sudo ps -aef | grep openconnect
sudo kill -9 $(pidof openconnect)
}
The issue is with eval:
VAR2=eval $(sudo ps -aef | grep openconnect)
Here, eval will try to execute the output of sudo ps -aef | grep openconnect command. That's the reason you are getting the errors you are seeing.
Rewrite it as:
VAR2=$(sudo ps -aef | grep openconnect)
Which will simply assign the output of the sudo command pipeline to VAR2 variable. However, you can't use VAR2 as an argument to kill because it contains other tokens like username along with the PID.
In other places where you are doing eval $(command), all you need is command.
You could use pkill openconnect to kill any existing openconnect processes instead of finding out the PID and issuing a kill against it. pgrep and pkill are quite handy for start/stop/restart script like yours.

Resources