I am trying to write a bash script that detects if a service has changed state. I have this so far:
while true; do
if [ -z "$(netstat -tulpn | grep 51827)" ];
then
echo notinuse
else
echo inuse
fi
sleep 5
done
It works but it will endlessly write when the service is up or down, and I only want it to report on the first instance of a state change. So report when the service was down, and then up as well as when it was up and then went down.
I started to create loop counters and comparing to a previous run but I got into a complete mess of variables. Can anyone help?
if [ -z "$(netstat -tulpn | grep 51827)" ];
then
echo notinuse
notify_status="notinuse-sent"
else
echo inuse
notify_status="inuse-sent"
fi
while true; do
if [ -z "$(netstat -tulpn | grep 51827)" ];
then
if [ $notify_status = "notinuse-sent" ]; then
echo "already notified"
else
echo notinuse
$notify_status="notinuse-sent"
fi
else
if [ $notify_status = "inuse-sent" ]; then
echo "already notified"
else
echo inuse
$notify_status="inuse-sent"
fi
fi
sleep 5
done
I'm really sorry to annoy to you again with my problem but it seems I'm about to finish. My goal is to create a bash-script that checks if a IP-address is still online or a scrub is in progress and if not that my systems shuts down. My script, which is currently in use, looks like this
#!/bin/bash
hosts=(
10.10.0.100 #Client 1
10.10.0.101 #Client 2
10.10.0.102 #Client 3
10.10.0.103 #Client 4
10.10.0.104 #Client 5
)
for host in "${hosts[#]}"; do
if ping -c 1 -i 1 "$host" >/dev/null; then
echo "No Shutdown - At least one PC ($host) is online"
exit 0
fi
done
echo "No PC is online - Shutdown"
bash shutdown -p now
I did some research and found the following command, to check if my scrub is in progress
if [ $(zpool status | grep 'scrub in progress') ]; then
echo "No Shutdown - Scrub in progess"
exit 0
fi
But i have problems in combining these two. I want my script to first check the IPs and if they all are offline then check for a scrub before it shuts down the machine. So both if-cases have to be false (ips offline and scrub not in progress) but they should be processed chronological and if the first if-case returns a IP which is online the script should stop.
Maybe somebody can help me?
To check if a command output contains a string, just:
if zpool status | grep -q 'scrub in progress'; then
The [ $(zpool status | grep 'scrub in progress') ] is invalid. The $( .. ) will expand to multiple words and will run [ scrub in progress ]. Because in is not a valid operator for [, then [ will print an error message and exit with 2. Just check the error status of grep.
For me, the answer is trivial:
hosts=(
10.10.0.100 #Client 1
10.10.0.101 #Client 2
10.10.0.102 #Client 3
10.10.0.103 #Client 4
10.10.0.104 #Client 5
)
for host in "${hosts[#]}"; do
if ping -c 1 -i 1 "$host" >/dev/null; then
echo "No Shutdown - At least one PC ($host) is online"
exit 0
fi
done
if $(zpool status | grep 'scrub in progress'); then
echo "No Shutdown - Scrub in progess"
exit 0
fi
echo "No PC is online and Scrub is not in progress - Shutdown"
shutdown -p now
Or did I miss the point?
Mind a couple of corrections inside of your code: remove the square brackets around the if test and remove the bash before shutdown.
You can negate the exit status by using !
if ! ping -c 1 -i 1 "$host" >/dev/null; then
if ! [[ $(zpool status | grep 'scrub in progress') ]]; then
echo "No PC is online - Shutdown"
bash shutdown -p now
fi
fi
## Add the rest of the script here if both conditions are true.
That basically means both condition are false, meaning there is no host up and scrub is not in progress, the opposite without the !
Check if both conditions are true just remove the !
if ping -c 1 -i 1 "$host" >/dev/null; then
if [[ $(zpool status | grep 'scrub in progress') ]]; then
echo "No Shutdown - At least one PC ($host) is online"
exit 0
fi
fi
Check if hosts are up but scrub is not running.
if ping -c 1 -i 1 "$host" >/dev/null; then
if ! [[ $(zpool status | grep 'scrub in progress') ]]; then
##: Add/run/execute your code here to start scrub.
fi
fi
If Nesting is what you want that would be something like.
for host in "${hosts[#]}"; do
if ping -c 1 -i 1 "$host" >/dev/null; then
echo "No Shutdown - At least one PC ($host) is online"
exit 0
elif ! ping -c 1 -i 1 "$host" >/dev/null; then
if ! [[ $(zpool status | grep 'scrub in progress') ]]; then
echo "No PC is online - Shutdown"
bash shutdown -p now
fi
fi
done
You can add the test for zpool inside the first if-statement.
for host in "${hosts[#]}"; do
if ping -c 1 -i 1 "$host" >/dev/null; then
if [[ $(zpool status | grep 'scrub in progress') ]]; then
echo "No Shutdown - At least one PC ($host) is online"
exit 0
fi
fi
elif ! ping -c 1 -i 1 "$host" >/dev/null; then
if ! [[ $(zpool status | grep 'scrub in progress') ]]; then
echo "No PC is online - Shutdown"
bash shutdown -p now
fi
fi
done
The first example set of if-statement should be enough though.
see help test
Question: How do you check if a PID exists and use the result within an IF statement in bash?
Things I've tried
if [ "$(ps -p $pid)" -eq 0 ]; then
echo "Running"
else
echo "Not Running"
fi
if [ "$(kill -0 $pid)" -eq 0 ]; then
echo "Running"
else
echo "Not Running"
fi
Neither of these evaluate correctly no matter how I redirect STDOUT/STDER
How do you check if a PID exists and use the result within an if statement?
You can capture the output in a variable and then check the exit status:
output=$(ps -p "$pid")
if [ "$?" -eq 0 ]; then
echo "Found"
echo "$output"
fi
Just remember that $? is getting reset every time you run a command, so something like the following wont work:
output=$(ps -p "$pid")
echo "$output"
# Now $? will be refering to the exit status of echo
if [ "$?" -eq 0 ]; then
echo "Found"
fi
One can also stick everything together in the if statement:
if output=$(ps -p "$pid")
then
echo "Found: $output"
fi
Make it dynamic by passing the pid you want to check:
#!/usr/local/bin/bash
if ps -p $1 > /dev/null;
then
echo "running"
else
echo "not running"
fi
Example runs:
What's your host OS?
If you have /proc then this may work for you:
if [ -d "/proc/$pid" ]; then
echo "Running"
else
echo "Not running"
fi
I'm new in Shellscript, and i'm getting some problems. I need a script to check if the services are running or not, if its not running, and dont exist the flag, start all services. What i'm doing wrong?
#!/bin/bash
file= "$PIN_HOME/apps/DE_BILL_MI_BRM/alarmistica/flags/intervencao.flag"
# Check if services are running
for service in $BRM_SERVICES
do
if [ps -ef | grep $service | grep -v grep | awk 'NR>1{for (i=1;i<=NF;i++)if($i==1) print "Services not running", i}' ]; then
echo $service " is not running correctly"
else
if [ -f "$file" ]; then
echo "Flag exists. The service will not start"
else
echo "$file not found. Starting all services"
pin_ctl start all
fi
fi
done
When ($i==1), the services is not running!
But the results is not corresponding. For exemple, when the services are down, the script dont start the services...
For checking process tables, use pgrep instead.
#!/bin/bash
file= "$PIN_HOME/apps/DE_BILL_MI_BRM/alarmistica/flags/intervencao.flag"
# Check if services are running
for service in $BRM_SERVICES
do
pgrep -f "$service";
exstat=$?; # This checks the exit status
if [ "$exstat" -eq 0 ] && ! [ -f "$file" ]; then
echo "pgrep returned exit status $extstat";
else
echo "$file not found. Starting all services"
pin_ctl start all
fi
done
This question already has answers here:
Linux Script to check if process is running and act on the result
(8 answers)
Closed 5 years ago.
I wrote a bash-script to check if a process is running. It doesn't work since the ps command always returns exit code 1. When I run the ps command from the command-line, the $? is correctly set, but within the script it is always 1. Any idea?
#!/bin/bash
SERVICE=$1
ps -a | grep -v grep | grep $1 > /dev/null
result=$?
echo "exit code: ${result}"
if [ "${result}" -eq "0" ] ; then
echo "`date`: $SERVICE service running, everything is fine"
else
echo "`date`: $SERVICE is not running"
fi
Bash version: GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
There are a few really simple methods:
pgrep procname && echo Running
pgrep procname || echo Not running
killall -q -0 procname && echo Running
pidof procname && echo Running
This trick works for me. Hope this could help you. Let's save the followings as checkRunningProcess.sh
#!/bin/bash
ps_out=`ps -ef | grep $1 | grep -v 'grep' | grep -v $0`
result=$(echo $ps_out | grep "$1")
if [[ "$result" != "" ]];then
echo "Running"
else
echo "Not Running"
fi
Make the checkRunningProcess.sh executable.And then use it.
Example to use.
20:10 $ checkRunningProcess.sh proxy.py
Running
20:12 $ checkRunningProcess.sh abcdef
Not Running
I tried your version on BASH version 3.2.29, worked fine. However, you could do something like the above suggested, an example here:
#!/bin/sh
SERVICE="$1"
RESULT=`ps -ef | grep $1 | grep -v 'grep' | grep -v $0`
result=$(echo $ps_out | grep "$1")
if [[ "$result" != "" ]];then
echo "Running"
else
echo "Not Running"
fi
I use this one to check every 10 seconds process is running and start if not and allows multiple arguments:
#!/bin/sh
PROCESS="$1"
PROCANDARGS=$*
while :
do
RESULT=`pgrep ${PROCESS}`
if [ "${RESULT:-null}" = null ]; then
echo "${PROCESS} not running, starting "$PROCANDARGS
$PROCANDARGS &
else
echo "running"
fi
sleep 10
done
Check if your scripts name doesn't contain $SERVICE. If it does, it will be shown in ps results, causing script to always think that service is running. You can grep it against current filename like this:
#!/bin/sh
SERVICE=$1
if ps ax | grep -v grep | grep -v $0 | grep $SERVICE > /dev/null
then
echo "$SERVICE service running, everything is fine"
else
echo "$SERVICE is not running"
fi
Working one.
!/bin/bash
CHECK=$0
SERVICE=$1
DATE=`date`
OUTPUT=$(ps aux | grep -v grep | grep -v $CHECK |grep $1)
echo $OUTPUT
if [ "${#OUTPUT}" -gt 0 ] ;
then echo "$DATE: $SERVICE service running, everything is fine"
else echo "$DATE: $SERVICE is not running"
fi
Despite some success with the /dev/null approach in bash. When I pushed the solution to cron it failed. Checking the size of a returned command worked perfectly though. The ampersrand allows bash to exit.
#!/bin/bash
SERVICE=/path/to/my/service
result=$(ps ax|grep -v grep|grep $SERVICE)
echo ${#result}
if ${#result}> 0
then
echo " Working!"
else
echo "Not Working.....Restarting"
/usr/bin/xvfb-run -a /opt/python27/bin/python2.7 SERVICE &
fi
#!/bin/bash
ps axho comm| grep $1 > /dev/null
result=$?
echo "exit code: ${result}"
if [ "${result}" -eq "0" ] ; then
echo "`date`: $SERVICE service running, everything is fine"
else
echo "`date`: $SERVICE is not running"
/etc/init.d/$1 restart
fi
Something like this
Those are helpful hints. I just needed to know if a service was running when I started the script, so I could leave the service in the same state when I left. I ended up using this:
HTTPDSERVICE=$(ps -A | grep httpd | head -1)
[ -z "$HTTPDSERVICE" ] && echo "No apache service running."
I found the problem. ps -ae instead ps -a works.
I guess it has to do with my rights in the shared hosting environment. There's apparently a difference between executing "ps -a" from the command line and executing it from within a bash-script.
A simple script version of one of Andor's above suggestions:
!/bin/bash
pgrep $1 && echo Running
If the above script is called test.sh then, in order to test, type:
test.sh NameOfProcessToCheck
e.g.
test.sh php
I was wondering if it would be a good idea to have progressive attempts at a process, so you pass this func a process name func_terminate_process "firefox" and it tires things more nicely first, then moves on to kill.
# -- NICE: try to use killall to stop process(s)
killall ${1} > /dev/null 2>&1 ;sleep 10
# -- if we do not see the process, just end the function
pgrep ${1} > /dev/null 2>&1 || return
# -- UGLY: Step trough every pid and use kill -9 on them individually
for PID in $(pidof ${1}) ;do
echo "Terminating Process: [${1}], PID [${PID}]"
kill -9 ${PID} ;sleep 10
# -- NASTY: If kill -9 fails, try SIGTERM on PID
if ps -p ${PID} > /dev/null ;then
echo "${PID} is still running, forcefully terminating with SIGTERM"
kill -SIGTERM ${PID} ;sleep 10
fi
done
# -- If after all that, we still see the process, report that to the screen.
pgrep ${1} > /dev/null 2>&1 && echo "Error, unable to terminate all or any of [${1}]" || echo "Terminate process [${1}] : SUCCESSFUL"
I need to do this from time to time and end up hacking the command line until it works.
For example, here I want to see if I have any SSH connections, (the 8th column returned by "ps" is the running "path-to-procname" and is filtered by "awk":
ps | awk -e '{ print $8 }' | grep ssh | sed -e 's/.*\///g'
Then I put it in a shell-script, ("eval"-ing the command line inside of backticks), like this:
#!/bin/bash
VNC_STRING=`ps | awk -e '{ print $8 }' | grep vnc | sed -e 's/.*\///g'`
if [ ! -z "$VNC_STRING" ]; then
echo "The VNC STRING is not empty, therefore your process is running."
fi
The "sed" part trims the path to the exact token and might not be necessary for your needs.
Here's my example I used to get your answer. I wrote it to automatically create 2 SSH tunnels and launch a VNC client for each.
I run it from my Cygwin shell to do admin to my backend from my windows workstation, so I can jump to UNIX/LINUX-land with one command, (this also assumes the client rsa keys have already been "ssh-copy-id"-ed and are known to the remote host).
It's idempotent in that each proc/command only fires when their $VAR eval's to an empty string.
It appends " | wc -l" to store the number of running procs that match, (i.e., number of lines found), instead of proc-name for each $VAR to suit my needs. I keep the "echo" statements so I can re-run and diagnose the state of both connections.
#!/bin/bash
SSH_COUNT=`eval ps | awk -e '{ print $8 }' | grep ssh | sed -e 's/.*\///g' | wc -l`
VNC_COUNT=`eval ps | awk -e '{ print $8 }' | grep vnc | sed -e 's/.*\///g' | wc -l`
if [ $SSH_COUNT = "2" ]; then
echo "There are already 2 SSH tunnels."
elif [ $SSH_COUNT = "1" ]; then
echo "There is only 1 SSH tunnel."
elif [ $SSH_COUNT = "0" ]; then
echo "connecting 2 SSH tunnels."
ssh -L 5901:localhost:5901 -f -l USER1 HOST1 sleep 10;
ssh -L 5904:localhost:5904 -f -l USER2 HOST2 sleep 10;
fi
if [ $VNC_COUNT = "2" ]; then
echo "There are already 2 VNC sessions."
elif [ $VNC_COUNT = "1" ]; then
echo "There is only 1 VNC session."
elif [ $VNC_COUNT = "0" ]; then
echo "launching 2 vnc sessions."
vncviewer.exe localhost:1 &
vncviewer.exe localhost:4 &
fi
This is very perl-like to me and possibly more unix utils than true shell scripting. I know there are lots of "MAGIC" numbers and cheezy hard-coded values but it works, (I think I'm also in poor taste for using so much UPPERCASE too). Flexibility can be added with some cmd-line args to make this more versatile but I wanted to share what worked for me. Please improve and share. Cheers.
A solution with service and awk that takes in a comma-delimited list of service names.
First it's probably a good bet you'll need root privileges to do what you want. If you don't need to check then you can remove that part.
#!/usr/bin/env bash
# First parameter is a comma-delimited string of service names i.e. service1,service2,service3
SERVICES=$1
ALL_SERVICES_STARTED=true
if [ $EUID -ne 0 ]; then
if [ "$(id -u)" != "0" ]; then
echo "root privileges are required" 1>&2
exit 1
fi
exit 1
fi
for service in ${SERVICES//,/ }
do
STATUS=$(service ${service} status | awk '{print $2}')
if [ "${STATUS}" != "started" ]; then
echo "${service} not started"
ALL_SERVICES_STARTED=false
fi
done
if ${ALL_SERVICES_STARTED} ; then
echo "All services started"
exit 0
else
echo "Check Failed"
exit 1
fi
The most simple check by process name :
bash -c 'checkproc ssh.exe ; while [ $? -eq 0 ] ; do echo "proc running";sleep 10; checkproc ssh.exe; done'