Check if service exists in bash (CentOS and Ubuntu)
Asked Answered
P

12

47

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?

Pickings answered 25/6, 2014 at 0:4 Comment(3)
User chkconfig <servicename> to check its presence. The return value is 0 if it is present and 1 if not. service <servicename> status returns the status of a service.Faulty
chkconfig <service> only returns true if the service is configured to run in the current runlevel (according to the man page I have here). chkconfig --list seems to have the desired behaviour here though (at the cost of success and failure output) but may or may not be any better than just checking for the existence of (and executability of) the init script itself.Jegar
In 2019, it appears that the answer may be best viewed through the eyes of systemd and systemctl.Charlettecharley
M
38

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.

Malloch answered 5/12, 2018 at 20:34 Comment(8)
I like this method, makes the check very clear in the script. So far, it's working well for me.Exeat
This is good but not the best. Some services like pure-ftpd will not be listed in systemctl list-units until you start it.Software
@ToiletGuy: in which case, the sytemctl list-units will return empty, and the function will return the correct resultMalloch
Do note: In Debian system it should be systemctl list-unit-files --all | grep "pure-ftpd". Using systemctl list-unit will not display the disabled service (but it only display enabled service). You can use my answer without having to print all unit files and filter the result which can be slower.Vertu
@Vertu And that a lack of superuser permissions (i.e., no sudo or root user caller) will return a reduced list of service filesZinnia
@Nick Bull What I meant was, using systemctl list-unit-files --all will display all services including disabled service, but systemctl list-unit will display all but not disabled service. So, it's a syntax issue (specific to Debian) not related to permission. I'm on root, tried your suggestion putting sudo before systemctl doesn't work.Vertu
Are you talking about list-unit-files or list-units? I'm referring to the formerZinnia
"in which case, the sytemctl list-units will return empty, and the function will return the correct result" - That does not make sense. You are checking if the service is exist and yes it does but it falsely reported it does not just because it was not running. In your case you should be checking is_service_running(){} not is_service_exists() {}Vertu
C
23

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
Cutthroat answered 14/1, 2015 at 20:23 Comment(6)
"service --status-all" writes services on unknown state to stderr. It might be convenient to use service --status-all 2>&1 | grep -Fq 'apache2'Senecal
If you need to ensure only 1 service is found, a trick you can use is a space in front of the service name. if service --status-all | grep -Fq ' cron'; then service cron start fi as cron will also match anacronGlobe
Shorter way to check both stdout and stderr in Bash: service --status-all |& grep -Fq 'apache2'.Justajustemilieu
This will first ping each service, and see its status. It can be quiete long to ping each service...Malloch
@JoséF.Romaniello Hi, may I know what -Fq command does? I googled it but didn't get a proper explanation.Mcfarland
@SandunI believe it's telling grep to use --fixed-strings and run in --quiet: tutorialspoint.com/unix_commands/grep.htmCutthroat
S
12

On a SystemD system :

serviceName="Name of your service"

if systemctl --all --type service | awk '$1 ~ '"/$serviceName/" >/dev/null;then
    echo "$serviceName exists."
else
    echo "$serviceName does NOT exist."
fi

On a Upstart system :

serviceName="Name of your service"

if initctl list | awk '$1 ~ '"/$serviceName/" >/dev/null;;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 | awk '$NF ~ '"/$serviceName/" >/dev/null;then
    echo "$serviceName exists."
else
    echo "$serviceName does NOT exist."
fi
Santana answered 14/3, 2020 at 12:8 Comment(2)
Example with systemctl --all --type service | grep -q "$serviceName" is flawed since systemctl --all --type service provides more info than just the service name so grep will search for the matches also at for example status or description column. I don't have services with name like: loaded, active, dead yet if I run the first example with serviceName=dead I get output dead exists.. You may narrow down grep match area by piping to awk or cut before grep and removing all the extraneous output of systemctl --all --type serviceMansell
@Mansell Thank you for this remark. I have updated my answer accordingly.Santana
V
5

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).

Vertu answered 24/2, 2021 at 4:18 Comment(2)
list-unit-files will not work for template units like <service_name>@<argument>.service since the command only lists the template file <service_name>@.service, not the activated service ID. Instead use systemctl list-units.Amazed
If-else is a bit redundant. You may just return the exit code of grep in the is_service_exists function since if grep don't find matches it exits with 1 and if finds a match then exits with 0. Therefore the whole if-else block can be replaced with just: systemctl status "${x}" 2> /dev/null | grep -Fq "Active:"; return $? where $? is the exit code of the previous command (grep in this case)Mansell
S
3
if systemctl cat xxx >/dev/null 2>&1; then
    echo yes
fi
Subalternate answered 4/11, 2022 at 15:48 Comment(1)
This is the best answer. I wonder why people hassle with piping to grep in other answers, when you can simply use the exit code, like it is shown here.Hematite
S
2

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
Shagbark answered 27/4, 2015 at 15:54 Comment(1)
don't know why but seams like some service status is printed to std_err so I had to add 2>&1 before the pipeFluoridate
C
2

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.

Charlettecharley answered 17/6, 2019 at 15:4 Comment(1)
This takes very long to load on a small computer. I believe this does way too much compared to the other solutions.Beardless
R
1
#!/bin/sh

service=mysql
status=$(/etc/init.d/mysql status)
print "$status"
#echo $status > /var/log/mysql_status_log
Roldan answered 12/7, 2016 at 1:34 Comment(0)
M
0
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

Madonia answered 18/2, 2020 at 14:54 Comment(1)
Your code compares literal string with another literal string: [ "output" != "" ] this will not work and always evaluate to the same result. Did you mean [ "${var:-}" != "" ] ? If so then you may write this also in different way [ -n "${var:-}" ]Mansell
D
0

extend from @jehon's answers. Simple grep -Fq option will easy lead to mistake I believe, if there are similar named service or applications.

However this?

service --status-all 2>&1 | grep -Pq '.*\s\Kxxx$'

Replace xxx with desired service or application name will match exactly the name.

Deloisedelong answered 27/11, 2023 at 6:50 Comment(0)
M
0

Shell function based on this answer

#!/bin/sh

set -eu

fn_service_exists() {
    systemctl cat "${1:-}" >/dev/null 2>&1
    return $?
}

test (on Ubuntu only)

fn_service_exists "cron" && echo "yes" || echo "no"
fn_service_exists "cron.service" && echo "yes" || echo "no"
fn_service_exists "missing" && echo "yes" || echo "no"

output

yes
yes
no
Mansell answered 3/4, 2024 at 17:11 Comment(0)
E
-1

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
Enarthrosis answered 25/6, 2014 at 5:20 Comment(2)
This assumes it is running. I don't want to check if the service is running, I want to see if the service is installed.Pickings
Maybe this one help service --status-all | grep mysql in this way you can check if service installed or not, if installed it gives you result,if not no result for related service.Enarthrosis

© 2022 - 2025 — McMap. All rights reserved.