The "proper" way to test if a service is running in a script
My problem:
I’m writing a bash script and in it I’d like to check if a given service is running.
I know how to do this manually, with $ service [service_name] status
.
But (especially since the move to systemd) that prints a whole bunch of text that’s a little messy to parse. I assumed there’s a command made for scripts with simple output or a return value I can check.
But Googling around only yields a ton of “Oh, just ps aux | grep -v grep | grep [service_name]
” results. That can’t be the best practice, is it? What if another instance of that command is running, but not one started by the SysV init script?
Or should I just shut up and get my hands dirty with a little pgrep?
systemctl
does have a mode suitable for scripting; use show
rather than status
, and add the -p
/ --properties
and --value
options to get only the output you want.
Here’s an example (from an Ubuntu 17.04 system):
$ systemctl show -p SubState --value NetworkManager
running
Running (or otherwise) is a SubState
. If you want to know whether a service is active, use the property ActiveState
$ systemctl show -p ActiveState --value x11-common
inactive
$ systemctl show -p SubState --value x11-common
dead
Notes from the man
:
show [PATTERN...|JOB...]
Show properties of one or more units, jobs, or the manager
itself. If no argument is specified, properties of the
manager will be shown. If a unit name is specified, properties
of the unit are shown, and if a job ID is specified,
properties of the job are shown. By default, empty properties
are suppressed. Use --all to show those too. To select specific
properties to show, use --property=. This command is intended
to be used whenever computer-parsable output is required. Use
status if you are looking for formatted human-readable output.
-p, --property=
When showing unit/job/manager properties with the show command,
limit display to properties specified in the argument. The
argument should be a comma-separated list of property names,
such as "MainPID". Unless specified, all known properties are
shown. If specified more than once, all properties with the
specified names are shown. Shell completion is implemented for
property names.
--value
When printing properties with show, only print the value, and
skip the property name and "=".
To see available properties for a service, run (for example, for polkit
)
systemctl show -a polkit
The possible values for LoadState
, ActiveState
and SubState
are unfortunately undocumented in the manpage(s); instead they are documented in the D-Bus interface description for org.freedesktop.systemd1
: https://www.freedesktop.org/software/systemd/man/org.freedesktop.systemd1.html
LoadState
contains a state value that reflects whether the configuration file of this unit has been loaded. The following states are currently defined: "loaded
", "error
", and "masked
". "loaded
" indicates that the configuration was successfully loaded. "error
" indicates that the configuration failed to load. TheLoadError
field (see below) contains information about the cause of this failure. "masked
" indicates that the unit is currently masked out (i.e. symlinked to/dev/null
or empty). Note that theLoadState
is fully orthogonal to theActiveState
(see below) as units without valid loaded configuration might be active (because configuration might have been reloaded at a time where a unit was already active).
ActiveState
contains a state value that reflects whether the unit is currently active or not. The following states are currently defined: "active
", "reloading
", "inactive
", "failed
", "activating
", and "deactivating
". "active
" indicates that unit is active (obviously…). "reloading
" indicates that the unit is active and currently reloading its configuration. "inactive
" indicates that it is inactive and the previous run was successful or no previous run has taken place yet. "failed
" indicates that it is inactive and the previous run was not successful (more information about the reason for this is available on the unit type specific interfaces, for example for services in the Result property, see below). "activating
" indicates that the unit has previously been inactive but is currently in the process of entering an active state. Conversely "deactivating
" indicates that the unit is currently in the process of deactivation.
SubState
encodes states of the same state machine thatActiveState
covers, but knows more fine-grained states that are unit-type-specific. WhereActiveState
only covers six high-level states,SubState
covers possibly many more low-level unit-type-specific states that are mapped to the six high-level states. Note that multiple low-level states might map to the same high-level state, but not vice versa. Not all high-level states have low-level counterparts on all unit types. At this point the low-level states are not documented here, and are more likely to be extended later on than the common high-level states explained above.
There are many properties, so if you know what you’re looking for…
$ systemctl show - polkit | grep Active
ActiveState=active
ActiveEnterTimestamp=Thu 2020-07-02 07:24:40 IST
ActiveEnterTimestampMonotonic=6682102
ActiveExitTimestamp=
ActiveExitTimestampMonotonic=0
systemctl
has an is-active
subcommand for this:
systemctl is-active --quiet service
will exit with status zero if service
is active, non-zero otherwise, making it ideal for scripts:
systemctl is-active --quiet service && echo Service is running
If you omit --quiet
it will also output the current status to its standard output.
Some units can be active even though nothing is running to provide the service: units marked as “RemainAfterExit” are considered active if they exit successfully, the idea being that they provide a service which doesn’t need a daemon (e.g. they configure some aspect of the system). Units involving daemons will however only be active if the daemon is still running.
Oneshot units without “RemainAfterExit” never enter the active unit state, so is-active
never succeeds; to handle such units, is-active
’s text output can be analysed instead:
systemctl is-active service
This will output “activating” for a oneshot unit that’s currently running, “inactive” for a oneshot unit that’s currently not running but was successful the last time it ran (if any), and “failed” for a oneshot unit that’s currently not running and failed the last time it ran. is-active
always returns a non-zero status with these units, so run
systemctl is-active service ||:
if you need to ignore that.
As a complement to Zanna’s answer, the --value
option for systemctl show
has been introduced with version 230 of systemd. So it may not be available on certain distros like debian jessie.
In this case, one can emulate the option by using sed:
$ systemctl show -p ActiveState sshd | sed 's/ActiveState=//g'
active
$ systemctl show -p SubState sshd | sed 's/SubState=//g'
running
Instead of using the sed command like in the answer of Oxmel, it is enough to use cut -d'=' -f 2
for all kind of properties queried:
for example:
$ systemctl show -p ActiveState sshd | cut -d'=' -f2
active
$ systemctl show -p SubState sshd | cut -d'=' -f2
running
i find this useful for command line execution or if you are making scripts.
Copied from @StephenKitt
This will check if the service is down and perform service restart
systemctl is-active --quiet <service name> || <service name> restart
the ||
there checks if the return value from systemctl is non-zero meaning if it’s not active as explained by the author.
I am too late to the party , however using systemctl is-active along with &&
and ||
to this in script wont be the case all the time. The below is one I used for tomcat but can use it in method taking arguments and pass service name as arguments if u have to check multiple services but its out of scope here.
STATUS="$(systemctl is-active tomcat.service)"
if [ "${STATUS}" = "active" ]; then
echo "Execute your tasks ....."
else
echo " Service not running.... so exiting "
exit 1
fi
This is how I made use of…. Just sharing mine.
and for the simplicity and easy stuffs, follow others explained here :
systemctl -q is-active tomcat.service &&
echo "Tomcat Runnung" ||
echo "Service is not running at all "
Have just found this great little script:
#!/bin/bash
service=replace_me_with_a_valid_service
if (( $(ps -ef | grep -v grep | grep $service | wc -l) > 0 ))
then
echo "$service is running!!!"
else
/etc/init.d/$service start
fi
There are many answers using systemctl
.
You have other options as well (where $?
comes handy):
- Using pidof command: suppose I am trying to find if redis-server is
running. First issuepidof redis-server
and then check the value of
$?
You will find 0 if it was running; non-zero otherwise. - Service specific solution: If the service provides a way to check if the service is running, you may use that. For the
redis-service
example, if the service is running, we will get a PONG response forredis-cli ping
command. After issuingredis-cli ping
, I’d check$?
and if it’s 0 then the service is running.
Also works for a non-systemd OS.
What about ps -C service-name
?
check $?
for answer. If 0
it’s running, if 1
, it’s not running.
Example:
ps -C privoxy && echo running
The quiet version:
ps -C privoxy 1>/dev/null && echo running
Caveat:
I noticed that service-names longer than 14 characters can give a false positive.
Also, see comment by ”Nick S”.
Example:
Correctly shows running:
$ ps -C notification-daemon
PID TTY TIME CMD
7418 ? 00:00:04 notification-da
Incorrectly shows running:
$ ps -C notification-daemon-fake
PID TTY TIME CMD
7418 ? 00:00:04 notification-da
Correctly shows not running because less that 14 characters:
$ ps -C notification
PID TTY TIME CMD
I got this answer from here.
this is for init.d system
if service is not running then start service:
service mysql status > /dev/null || service mysql start &
service ssh status > /dev/null || service ssh start &
service php7.4-fpm status > /dev/null || service php7.4-fpm start &
service redis-server status > /dev/null || service redis-server start &
service nginx status > /dev/null || service nginx start &
service cron status > /dev/null || service cron start &
when a program exits it returns also an error id, a signed byte.
on exit without problems, the value is usually 0.
on exit because of errors, the value is usually error id or frequently -1.
this value is frequently used for command integration like the numeric status id of the printed program output.
to use it with command chaining the are two options && and ||
the || checks if the exit return value is not a zero, then it runes the chained command
instead of || it impossible to write &&
the && checks if the exit return value is a zero, then it runes the chained command
similar to @asterisk answer on this page (for systemd)
https://unix.stackexchange.com/a/500336/156304
You can use if/else in your bash script, as example for service
service:
if (systemctl is-active --quiet service); then
echo -e "SERVICE is Running!"
else
echo -e "SERVICE has Stopped status!"
fi
Absolutely shameless plug since I’m the author, but I’d recommend checking out the service::linux
task from the Puppet Service module. It’s pure Bash and comes bundled with Bolt, so you don’t actually need to use Puppet at all. e.g.
$ bolt task run service::linux action=status name=sshd --targets localhost
{
"status": "MainPID=1358,LoadState=loaded,ActiveState=active",
"enabled": "enabled"
}
The code uses systemctl show
, which is here. It’s been in use long enough that I feel confident in recommending it, and issues and PRs are welcome to be submitted.