how to determine if the service exists in shell [duplicate] - shell

What is the best way in bash to check if a service is installed? It should work across both Red Hat (CentOS) and Ubuntu?
Thinking:
service="mysqld"
if [ -f "/etc/init.d/$service" ]; then
# mysqld service exists
fi
Could also use the service command and check the return code.
service mysqld status
if [ $? = 0 ]; then
# mysqld service exists
fi
What is the best solution?

To get the status of one service without "pinging" all other services, you can use the command:
systemctl list-units --full -all | grep -Fq "$SERVICENAME.service"
By the way, this is what is used in bash (auto-)completion (see in file /usr/share/bash-completion/bash_completion, look for _services):
COMPREPLY+=( $( systemctl list-units --full --all 2>/dev/null | \
awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' ) )
Or a more elaborate solution:
service_exists() {
local n=$1
if [[ $(systemctl list-units --all -t service --full --no-legend "$n.service" | sed 's/^\s*//g' | cut -f1 -d' ') == $n.service ]]; then
return 0
else
return 1
fi
}
if service_exists systemd-networkd; then
...
fi
Hope to help.

Rustam Mamat gets the credit for this:
If you list all your services, you can grep the results to see what's in there. E.g.:
# Restart apache2 service, if it exists.
if service --status-all | grep -Fq 'apache2'; then
sudo service apache2 restart
fi

On a SystemD system :
serviceName="Name of your service"
if systemctl --all --type service | grep -q "$serviceName";then
echo "$serviceName exists."
else
echo "$serviceName does NOT exist."
fi
On a Upstart system :
serviceName="Name of your service"
if initctl list | grep -q "$serviceName";then
echo "$serviceName exists."
else
echo "$serviceName does NOT exist."
fi
On a SysV (System V) system :
serviceName="Name of your service"
if service --status-all | grep -q "$serviceName";then
echo "$serviceName exists."
else
echo "$serviceName does NOT exist."
fi

In systemd (especially in Debian), it doesn't seems to work properly using the various answers from here. For some services like pure-ftpd if it's in disabled mode, it will not show up in service list when you trigger this command:
systemctl --all --type service
and when you start again the pure-ftpd with systemctl start pure-ftpd the list will appear again. So listing the service using systemctl --all --type service will not work for all services. Take a look at this for more information.
So, this is the best code so far (improvement from #jehon's answer) to check if a service is exist (even it has status inactive, dead or whatever status it is):
#!/bin/bash
is_service_exists() {
local x=$1
if systemctl status "${x}" 2> /dev/null | grep -Fq "Active:"; then
return 0
else
return 1
fi
}
if is_service_exists 'pure-ftpd'; then
echo "Service found!"
else
echo "Service not found!"
fi
Explanation:
If systemctl status found a service, it must have a text 'Active:' we filter using grep and it would return 0. If there is no 'Active:' text it would return 1.
If systemctl status does not find the 'Active:' text, it will print out a standard error. So, I put redirection 2> /dev/null to redirect the standard error. For example, if you are looking for the non existence service, you would get this error message if you don't put that error redirection:
Unit pure-ftpdd.service could not be found.
We don't want to have the above standard error message if you are doing scripting
EDIT:
Another method is to list out unit files which able to detect disabled service as pointed by #Anthony Rutledge for Debian system:
systemctl list-unit-files --type service | grep -F "pure-ftpd"
But using this method will not always work especially for older system because some unit files might not be detected using this command as explained in here. Also, using this method is slower if you have large unit-files that need to be filtered (as commented by #ygoe about heavy load on a small computer).

To build off of Joel B's answer, here it is as a function (with a bit of flexibility added in. Note the complete lack of parameter checking; this will break if you don't pass in 2 parameters):
#!/bin/sh
serviceCommand() {
if sudo service --status-all | grep -Fq ${1}; then
sudo service ${1} ${2}
fi
}
serviceCommand apache2 status

After reading some systemd man pages ...
https://www.freedesktop.org/software/systemd/man/systemd.unit.html
... and systemd.services(5)....
... and a nice little article ...
https://www.linux.com/learn/understanding-and-using-systemd
I believe this could be an answer.
systemctl list-unit-files --type service
Pipe to awk {'print $1'} to just get a listing of the service units.
Pipe to awk again to get the service names exclusively. Change the field separator to the period with -F.
awk -F. {'print $1'}
In summary:
systemctl list-unit-files --type service | awk {'print $1'} | awk -F. {'print $1'}
With variation and augmentation of the base solution, you can determine the state of your system's services by combining a for loop with systemctl is-active $service.

#!/bin/sh
service=mysql
status=$(/etc/init.d/mysql status)
print "$status"
#echo $status > /var/log/mysql_status_log

var=$(service --status-all | grep -w "$Service")
if [ "output" != "" ]; then
#executes if service exists
else
#executes if service does not exist
fi
$Service is the name of the service you want to know if exists.
var will contain something like
[+] apache2
if the service does exist

if systemctl cat xxx >/dev/null 2>&1; then
echo yes
fi

Try this, as ps command can be used in both Ubuntu&RHEL, this should be work in both platform.
#!/bin/bash
ps cax | grep mysqld > /dev/null
if [ $? -eq 0 ]; then
echo "mysqld service exists"
else
echo "mysqld service not exists"
fi

Related

Bash - start multiple services if any is running CentOS 6.8

I want to check if one, (or all) services are running, if yes, stop it
#!/bin/bash
# Define an array of processes to be checked.
# If properly quoted, these may contain spaces
check_process=( "nagios" "httpd" )
for p in "${check_process[#]}"; do
if pgrep "$p" > /dev/null; then
echo "Process \`$p' is running, stopping it"
service $p stop
else
echo "Process \`$p' is not running"
fi
done
For httpd service all works fine, script detects correctly httpd service state.
I have issues detecting nagios service state.
But although nagios service is not running, script shows it's running
Process `nagios' is running, stopping it
Stopping nagios:No lock file found in /usr/local/nagios/var/nagios.lock
Process `httpd' is not running
Is there any more elegant way of detecting if nagios service is running without checking if nagios.lock file exists ?
pgrep nagios shows no output when service is not tunning.
I gave up, this works fine for me:
although ps -ef | grep -v grep | grep $service | wc -l shows 0 for nagios, script reports that nagios service is running
#!/bin/bash
logfile=/tmp/stop_nagios.txt
exec >> $logfile
exec 2>&1
service=httpd
if (( $(ps -ef | grep -v grep | grep $service | wc -l) > 0 ))
then
echo "$service is running, stopping it"
date
sudo service $service stop
else
echo "$service is not running"
fi
# check nagios service
FILE=/usr/local/nagios/var/nagios.lock
if test -f "$FILE"; then
echo "nagios service is running, stopping it"
date
sudo service nagios stop
else
echo "nagios is not running..."
fi

bash script: to check if Apache server is up and running

I am new to bash scripting and trying to figure out why the below script is outputting that Apache server is not running whereas it is running properly.
ps cax | grep httpd
if [ $? -eq 0 ]; then
echo "Process is running."
else
echo "Process is not running."
fi
I'm running it on Ubuntu 14.04.2 LTS
Also, how do I make changes to the script that this can test apache server installed on another machine.
Kindly help
This is a working sample of bash script which check the apache status, restart it automatically if down, and alert by telegram bot within unicode emoji.
#!/bin/bash
telegram=(xxxxx, yyyyyy)
if ! pidof apache2 > /dev/null
then
# web server down, restart the server
echo "Server down"
/etc/init.d/apache2 restart > /dev/null
sleep 10
#checking if apache restarted or not
if pidof apache2 > /dev/null
then
for i in "${telegram[#]}"
do
curl -s -X POST https://api.telegram.org/botxxxxxx:yyyyyyyyyyyyyyyyyyyyyyyyyy/sendMessage -d chat_id="$i" -d text="`echo -e '\U0001F525'` Apache stoped on Molib Stage. Automatically restarted succesfully."
done
else
for i in "${telegram[#]}"
do
curl -s -X POST https://api.telegram.org/botxxxxxx:yyyyyyyyyyyyyyyyyyyyyyyyyy/sendMessage -d chat_id="$i" -d text="`echo -e '\U0001F525'` Apache stoped on Molib Stage. Automatically restart failed. Please check manually."
done
fi
fi
Use this:
service apache2 status
Or this:
service --status-all | grep apache2
Instead of httpd try to grep "apache2". To be sure try to check services with the next command and decide the registered name of the apache webserver:
service --status-all
Try and see - simply simplest, most didactic here and well working on Ubuntu 20.04:
catching output of status to bash variable
"if" status includes substring (from "Active:" statement) - do job you wanted
"else" - do another job you defined
#!/bin/bash
servstat=$(service apache2 status)
if [[ $servstat == *"active (running)"* ]]; then
echo "process is running"
else echo "process is not running"
fi
This work perfect in an old Debian. Remember to run with bash and not with sh.
In Centos replace with httpd.
#!/bin/bash
if [ $(/etc/init.d/apache2 status | grep -v grep | grep 'apache2 is running' | wc -l) > 0 ]
then
echo "Process is running."
else
echo "Process is not running."
fi
## Plz run this script .. its working
------------------------------------------------
ps cax | grep httpd
if [ $? -eq 1 ]
then
echo "Process is running."
else if [ $? -eq 0 ]
echo "Process is not running."
fi
fi
----------------------------------------------
This is menu driven one stop shell script in which you can check the firewall,apache or any other webservices ,you can start or stop the services just by choosing the option in below script
echo "welcome please select your options"
read choice
firewall=`sudo systemctl status firewalld`
apache=`sudo systemctl status apache2`
firewall1=`sudo systemctl stop firewalld`
apache1=`sudo systemctl stop apache2`
startrfirewall=`sudo systemctl start firewalld`
startapache=`sudo systemctl start apache2`
case $choice in
1) status of the firewall is $firewall
;;
2) status of apache is $apache
;;
3) echo stop firewall by $firewall1
;;
4) echo stop apache by $apache1
;;
5) echo start firewall by $startrfirewall
;;
6) echo start apache by $startapache
;;
*) echo exit
esac
I put this together based on the above and made so can use other services.
Hope this helps.
#!/bin/bash
# Must be running as root or via sudo permissions to be able to restart
# Put your process name restart command line in
PROCESS_NAME=httpd
if ! pidof $PROCESS_NAME > /dev/null
then
# web server down, restart the server
echo "Server $PROCESS_NAME down"
/usr/sbin/apachectl restart > /dev/null
echo "Tried restart of $PROCESS_NAME. Waiting 10 seconds to settle."
# wait ten
sleep 10
#checking if process restarted or not
if pidof $PROCESS_NAME > /dev/null
then
echo "$PROCESS_NAME was down but is now up."
else
echo "$PROCESS_NAME is still down. Please take some action."
fi
else
echo "Server $PROCESS_NAME up."
fi

To check whether nohup service is running or not using shell script?

I had created a nohup service using the below command in putty.
nohup php /var/www/html/XYZ/sample.php &
This command executes the sample.php file in background.
Now what i need is i want a shell script which checks whether this service is running or not.Incase if the service is not running i want that shell script to create a service by its own. Below is the code what i tried.
#!/bin/bash
email_to="xyz#gmail.com";
export DISPLAY=:0.0
PIDS=`ps -aux | grep sample.php|awk '{print $2}'`
if [ -z "$PIDS" ]; then
echo "$(date) - The service is not running. Sending email to :$email_to" >> /var/www/html/XYZ/sample.php;
echo "SERVICE is not running - $(date)" | mail -s "service is not running - $(date)" $email_to
echo "" >> /var/www/html/XYZ/sample.php;
exit 1
else
echo "$(date) - Service already running. Sending email to : $email_to" >> /var/www/html/XYZ/sample.php;
echo "SERVICE is running - $(date)" | mail -s "SERVICE is running - $(date)" $email_to
fi
when i execute the file i get the mail as service is running ,and once i kill the sample.php and when i get execute this file i get the same mail "as service is running" but its wrong ,so can anyone direct me where have i gone wrong?
where have i gone wrong?
With ps -aux | grep sample.php, the grep is finding sample.php in its own process command line grep sample.php, also output by ps. This can be avoided by modifying the grep command so that it doesn't contain sample.php literally, e. g. grep 'sample\.php' (which by the way averts the risk of matching another character instead of the .). You'll probably also need wide output from ps to not truncate the command, so change the above pipeline to ps waux | grep 'sample\.php'.

Tomcat 7 monitoring with e-mail notifications

I've been looking for a bit but can't find a free/open-source tomcat 7 monitoring tool that will send out e-mails or notifications when certain situations occur. For example when CPU utilization spikes or RAM is consistently full. Things Like that.
I've looked at JMelody and Psi-Probe and neither of them have the ability to send e-mails when some event occurs.
You can take a look at jboss RHQ
https://docs.jboss.org/author/display/RHQ/Alerts
This might help someone!!
If one do not want to use any monitoring tool, then set up an email configurtion in Ubuntu server using mailutils package.
https://rianjs.net/2013/08/send-email-from-linux-server-using-gmail-and-ubuntu-two-factor-authentication
https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-14-04
To monitor Tomcat status you can use below script and set up cron job which runs every minute/hour/day according to your needs.
#!/bin/bash
TOMCAT_HOME=/opt/tomcat
PUBLIC_IP=`wget http://ipecho.net/plain -O - -q ; echo`
EMAIL_BODY="Hi Admin,\n\n$PUBLIC_IP Tomcat is down at $(date -d "+330 minutes" +"%Y-%m-%d %T") IST, Please take necessary action.\n\n\nDo not reply to this email as it is auto generated by Ubuntu system\n"
tomcat_pid() {
echo `ps aux | grep org.apache.catalina.startup.Bootstrap | grep -v grep | awk '{ print $2 }'`
}
start() {
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Tomcat is already running (pid: $pid)"
else
# Start tomcat
echo "Starting tomcat"
/bin/sh $TOMCAT_HOME/bin/startup.sh
fi
return 0
}
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Tomcat is running with pid: $pid"
#stop
else
echo "Tomcat is not running"
# send an email alert then start
echo -e $EMAIL_BODY | mail -s "$PUBLIC_IP Tomcat is down" user#email.com
echo "Mail sent"
#remove cache and release memory occupied by heavy processes
start
fi
exit 0

How to test an Internet connection with bash?

How can an internet connection be tested without pinging some website?
I mean, what if there is a connection but the site is down? Is there a check for a connection with the world?
Without ping
#!/bin/bash
wget -q --spider http://google.com
if [ $? -eq 0 ]; then
echo "Online"
else
echo "Offline"
fi
-q : Silence mode
--spider : don't get, just check page availability
$? : shell return code
0 : shell "All OK" code
Without wget
#!/bin/bash
echo -e "GET http://google.com HTTP/1.0\n\n" | nc google.com 80 > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Online"
else
echo "Offline"
fi
Ping your default gateway:
#!/bin/bash
ping -q -w 1 -c 1 `ip r | grep default | cut -d ' ' -f 3` > /dev/null && echo ok || echo error
Super Thanks to user somedrew for their post here: https://bbs.archlinux.org/viewtopic.php?id=55485 on 2008-09-20 02:09:48
Looking in /sys/class/net should be one way
Here's my script to test for a network connection other than the loop back.
I use the below in another script that I have for periodically testing if my website is accessible. If it's NOT accessible a popup window alerts me to a problem.
The script below prevents me from receiving popup messages every five minutes whenever my laptop is not connected to the network.
#!/usr/bin/bash
# Test for network conection
for interface in $(ls /sys/class/net/ | grep -v lo);
do
if [[ $(cat /sys/class/net/$interface/carrier) = 1 ]]; then OnLine=1; fi
done
if ! [ $OnLine ]; then echo "Not Online" > /dev/stderr; exit; fi
Note for those new to bash: The final 'if' statement tests if NOT [!] online and exits if this is the case. See man bash and search for "Expressions may be combined" for more details.
P.S. I feel ping is not the best thing to use here because it aims to test a connection to a particular host NOT test if there is a connection to a network of any sort.
P.P.S. The Above works on Ubuntu 12.04 The /sys may not exist on some other distros. See below:
Modern Linux distributions include a /sys directory as a virtual filesystem (sysfs, comparable to /proc, which is a procfs), which stores and allows modification of the devices connected to the system, whereas many traditional UNIX and Unix-like operating systems use /sys as a symbolic link to the kernel source tree.[citation needed]
From Wikipedia https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
This works on both MacOSX and Linux:
#!/bin/bash
ping -q -c1 google.com &>/dev/null && echo online || echo offline
In Bash, using it's network wrapper through /dev/{udp,tcp}/host/port:
if : >/dev/tcp/8.8.8.8/53; then
echo 'Internet available.'
else
echo 'Offline.'
fi
(: is the Bash no-op, because you just want to test the connection, but not processing.)
The top answer misses the fact that you can have a perfectly stable connection to your default gateway but that does not automatically mean you can actually reach something on the internet. The OP asks how he/she can test a connection with the world. So I suggest to alter the top answer by changing the gateway IP to a known IP (x.y.z.w) that is outside your LAN.
So the answer would become:
ping -q -w 1 -c 1 x.y.z.w > /dev/null && echo ok || echo error
Also removing the unfavored backticks for command substitution[1].
If you just want to make sure you are connected to the world before executing some code you can also use:
if ping -q -w 1 -c 1 x.y.z.w > /dev/null; then
# more code
fi
I've written scripts before that simply use telnet to connect to port 80, then transmit the text:
HTTP/1.0 GET /index.html
followed by two CR/LF sequences.
Provided you get back some form of HTTP response, you can generally assume the site is functioning.
make sure your network allow TCP traffic in and out, then you could get back your public facing IP with the following command
curl ifconfig.co
Execute the following command to check whether a web site is up, and what status message the web server is showing:
curl -Is http://www.google.com | head -1 HTTP/1.1 200 OK
Status code ‘200 OK’ means that the request has succeeded and a website is reachable.
The top voted answer does not work for MacOS so for those on a mac, I've successfully tested this:
GATEWAY=`route -n get default | grep gateway`
if [ -z "$GATEWAY" ]
then
echo error
else
ping -q -t 1 -c 1 `echo $GATEWAY | cut -d ':' -f 2` > /dev/null && echo ok || echo error
fi
tested on MacOS High Sierra 10.12.6
If your local nameserver is down,
ping 4.2.2.1
is an easy-to-remember always-up IP (it's actually a nameserver, even).
This bash script continuously check for Internet and make a beep sound when the Internet is available.
#!/bin/bash
play -n synth 0.3 sine 800 vol 0.75
while :
do
pingtime=$(ping -w 1 8.8.8.8 | grep ttl)
if [ "$pingtime" = "" ]
then
pingtimetwo=$(ping -w 1 www.google.com | grep ttl)
if [ "$pingtimetwo" = "" ]
then
clear ; echo 'Offline'
else
clear ; echo 'Online' ; play -n synth 0.3 sine 800 vol 0.75
fi
else
clear ; echo 'Online' ; play -n synth 0.3 sine 800 vol 0.75
fi
sleep 1
done
Similarly to #Jesse's answer, this option might be much faster than any solution using ping and perhaps slightly more efficient than #Jesse's answer.
find /sys/class/net/ -maxdepth 1 -mindepth 1 ! -name "*lo*" -exec sh -c 'cat "$0"/carrier 2>&1' {} \; | grep -q '1'
Explenation:
This command uses find with -exec to run command on all files not named *lo* in /sys/class/net/. These should be links to directories containing information about the available network interfaces on your machine.
The command being ran is an sh command that checks the contents of the file carrier in those directories. The value of $interface/carrier has 3 meanings - Quoting:
It seems there are three states:
./carrier not readable (for instance when the interface is disabled in Network Manager).
./carrier contain "1" (when the interface is activated and it is connected to a WiFi network)
./carrier contain "0" (when the interface is activated and it is not connected to a WiFi network)
The first option is not taken care of in #Jesse's answer. The sh command striped out is:
# Note: $0 == $interface
cat "$0"/carrier 2>&1
cat is being used to check the contents of carrier and redirect all output to standard output even when it fails because the file is not readable.
If grep -q finds "1" among those files it means there is at least 1 interface connected. The exit code of grep -q will be the final exit code.
Usage
For example, using this command's exit status, you can use it start a gnubiff in your ~/.xprofile only if you have an internet connection.
online() {
find /sys/class/net/ -maxdepth 1 -mindepth 1 ! -name "*lo*" -exec sh -c 'cat "$0"/carrier 2>&1 > /dev/null | grep -q "1" && exit 0' {} \;
}
online && gnubiff --systemtray --noconfigure &
Reference
Help testing special file in /sys/class/net/
find -exec a shell function?
shortest way: fping 4.2.2.1 => "4.2.2.1 is alive"
i prefer this as it's faster and less verbose output than ping, downside is you will have to install it.
you can use any public dns rather than a specific website.
fping -q google.com && echo "do something because you're connected!"
-q returns an exit code, so i'm just showing an example of running something you're online.
to install on mac: brew install fping; on ubuntu: sudo apt-get install fping
Ping was designed to do exactly what you're looking to do. However, if the site blocks ICMP echo, then you can always do the telnet to port 80 of some site, wget, or curl.
Checking Google's index page is another way to do it:
#!/bin/bash
WGET="/usr/bin/wget"
$WGET -q --tries=20 --timeout=10 http://www.google.com -O /tmp/google.idx &> /dev/null
if [ ! -s /tmp/google.idx ]
then
echo "Not Connected..!"
else
echo "Connected..!"
fi
For the fastest result, ping a DNS server:
ping -c1 "8.8.8.8" &>"/dev/null"
if [[ "${?}" -ne 0 ]]; then
echo "offline"
elif [[ "${#args[#]}" -eq 0 ]]; then
echo "online"
fi
Available as a standalone command: linkStatus
Pong doesn't mean web service on the server is running; it merely means that server is replying to ICMP echo.
I would recommend using curl and check its return value.
If your goal is to actually check for Internet access, many of the existing answers to this question are flawed. A few things you should be aware of:
It's possible for your computer to be connected to a network without that network having internet access
It's possible for a server to be down without the entire internet being inaccessible
It's possible for a captive portal to return an HTTP response for an arbitrary URL even if you don't have internet access
With that in mind, I believe the best strategy is to contact several sites over an HTTPS connection and return true if any of those sites responds.
For example:
connected_to_internet() {
test_urls="\
https://www.google.com/ \
https://www.microsoft.com/ \
https://www.cloudflare.com/ \
"
processes="0"
pids=""
for test_url in $test_urls; do
curl --silent --head "$test_url" > /dev/null &
pids="$pids $!"
processes=$(($processes + 1))
done
while [ $processes -gt 0 ]; do
for pid in $pids; do
if ! ps | grep "^[[:blank:]]*$pid[[:blank:]]" > /dev/null; then
# Process no longer running
processes=$(($processes - 1))
pids=$(echo "$pids" | sed --regexp-extended "s/(^| )$pid($| )/ /g")
if wait $pid; then
# Success! We have a connection to at least one public site, so the
# internet is up. Ignore other exit statuses.
kill -TERM $pids > /dev/null 2>&1 || true
wait $pids
return 0
fi
fi
done
# wait -n $pids # Better than sleep, but not supported on all systems
sleep 0.1
done
return 1
}
Usage:
if connected_to_internet; then
echo "Connected to internet"
else
echo "No internet connection"
fi
Some notes about this approach:
It is robust against all the false positives and negatives I outlined above
The requests all happen in parallel to maximize speed
It will return false if you technically have internet access but DNS is non-functional or your network settings are otherwise messed up, which I think is a reasonable thing to do in most cases
If you want to handle captive portals, you can do this oneliner:
if [[ $(curl -s -D - http://www.gstatic.com/generate_204 2>/dev/null | head -1 | cut -d' ' -f 2) == "204" ]]; then
echo 'online'
else
echo 'offline'
fi
Or if you want something more readable that can differentiate captive portals from lack of signal:
function is_online() {
# Test signal
local response
response=$(curl --silent --dump-header - http://www.gstatic.com/generate_204 2> /dev/null)
if (($? != 0)); then return 2; fi
# Test captive portal
local status=$(echo $response | head -1 | cut -d' ' -f 2)
((status == "204"))
}
is_online && echo online || echo offline

Resources