systemctl list-units —type=service —state=running shows what is actually running. Everything else on this page is about making that output readable or scriptable.
The command itself is not hard. What makes this annoying in practice is that the default output opens a pager, wraps in narrow terminals, and includes a legend you never wanted — so the thing you actually needed scrolls past.
There is also a distinction worth getting straight early: a unit that is loaded is not necessarily running, and a service that is enabled is not necessarily started. Confusing those is the source of most “but I enabled it” conversations.
Table of contents
- The commands worth memorising
- Loaded, active, enabled: three different things
- Filtering to what you are actually looking for
- Investigating a single service
- Finding what is actually consuming the machine
- Inside a container, where none of this exists
- How this fits the rest of the stack
- FAQ
The commands worth memorising
# Currently running services
systemctl list-units --type=service --state=running
# Shorter, same result
systemctl --type=service --state=running
# No pager, no legend -- the version for a script
systemctl list-units --type=service --state=running --no-pager --no-legend
# Just the names, one per line
systemctl list-units --type=service --state=running \
--no-pager --no-legend --plain | awk '{print $1}'
--no-pager is the flag that saves the most irritation. Without it systemd pipes through less, which is unhelpful in a script and mildly annoying interactively.
--no-legend drops the explanatory footer, and --plain removes the leading status bullets. Together they give you parseable columns.
For a broader view including failures and everything installed.
# Anything failed -- run this first when something is wrong
systemctl --failed
# All services regardless of state
systemctl list-units --type=service --all
# Every installed unit file and whether it is enabled at boot
systemctl list-unit-files --type=service
Loaded, active, enabled: three different things
These get used interchangeably in conversation and they mean genuinely different things.
- LOAD — systemd has read the unit file.
not-foundmeans you have a typo or the package is missing. - ACTIVE — the high-level state: active, inactive, failed, activating, deactivating.
- SUB — the type-specific state. For a service: running, exited, dead, or failed.
- ENABLED — whether it starts at boot. Entirely independent of whether it is running now.
The pair that confuses people most is active (exited). That is not a failure — it is normal and correct for oneshot units that do a job and finish, like a firewall rule loader. The service did its work and stopped; systemd considers the state achieved.
The other trap is assuming enabled implies running. systemctl enable nginx creates a symlink so it starts at boot and does nothing right now. systemctl enable --now nginx does both, and is almost always what people meant.
Filtering to what you are actually looking for
# Combine states
systemctl list-units --type=service --state=running,failed
# Pattern match on the unit name
systemctl list-units 'ssh*' --no-pager
systemctl list-units '*nginx*' --all --no-pager
# Sockets, timers, and mounts are units too
systemctl list-units --type=timer --state=running
systemctl list-timers --all --no-pager
# What is enabled at boot but not currently running
systemctl list-unit-files --type=service --state=enabled --no-pager
list-timers deserves more attention than it gets. Systemd timers have largely replaced cron on modern distributions, and a scheduled job that is not firing will show up here with its next and last run times.
The --state=enabled listing against currently running services is a useful reconciliation. Anything enabled but not running either failed at boot or was stopped manually, and both are worth knowing about.
Investigating a single service
Once you have identified the interesting service, status gives you state, the main process ID, resource usage, and the last few log lines in one view.
systemctl status nginx
# Just the answer, for a script
systemctl is-active nginx # active / inactive / failed
systemctl is-enabled nginx # enabled / disabled / static / masked
systemctl is-failed nginx
# The full unit definition, including defaults you did not set
systemctl cat nginx
systemctl show nginx --property=MainPID,ExecStart,Restart
# Logs for that unit
journalctl -u nginx --since "1 hour ago" --no-pager
journalctl -u nginx -f
The is-active family is what belongs in scripts. They exit 0 or non-zero and print a single word, where parsing status output is fragile and version-dependent.
systemctl cat shows the unit file plus any drop-in overrides, which is how you discover the /etc/systemd/system/nginx.service.d/override.conf that somebody added and forgot to mention.
A service stuck in activating usually means the unit declares Type=notify and the process never sent its ready signal, or Type=forking and systemd is watching the wrong PID. Both show up in the journal.
Finding what is actually consuming the machine
The service list tells you what exists. These tell you what it costs.
# Per-unit resource accounting, top-style
systemd-cgtop
# Memory and CPU for one service
systemctl status nginx | grep -E 'Memory|CPU|Tasks'
# What is slowing down boot
systemd-analyze blame | head -20
systemd-analyze critical-chain
systemd-cgtop is the underused one. Because systemd puts each service in its own cgroup, it attributes CPU and memory per service rather than per process — which is far more useful when a service forks a dozen workers.
systemd-analyze blame is the first stop for slow boots. It ranks units by initialisation time, and the answer is frequently a network-wait unit sitting on a timeout for something that is not coming.
Inside a container, where none of this exists
Most containers run a single process as PID 1 with no init system at all, so every systemctl command fails with “System has not been booted with systemd as init system”.
That is correct behaviour, not a broken image. A container is one process, and process supervision belongs to the orchestrator outside it.
# Inside a container, use plain process tools
ps aux
cat /proc/1/cmdline
# From the host, the container IS the service
docker ps --format "table {{.Names}}\t{{.Status}}"
docker stats --no-stream
If you find yourself wanting systemd inside a container to supervise multiple processes, that is a signal the container is doing too much. Split it into one process per container and let the orchestrator handle restarts and dependencies.
How this fits the rest of the stack
Checking which services are running is usually the first move when something is wrong on a server — and the fact that it is the first move says something about how much operational surface a plain VPS gives you. RunxBuild runs services with health status, restart behaviour, and logs surfaced together, so a failing process is visible without connecting to a box. The RunxBuild hosting calculator shows what those services cost with that operational layer included, against the server you would otherwise be logging into.
Useful related references:
- Show CPU Usage on Linux: The Commands That Stay Useful
- How to Rename a File in Linux: mv, rename, and git mv
- hostnamectl set-hostname: How to Set the Hostname in Linux
- Services on RunxBuild
FAQ
How do I list only running services in Linux?
systemctl list-units --type=service --state=running. Add --no-pager --no-legend to strip the pager and the footer, which is what you want in a script.
What is the difference between enabled and active?
Enabled means the service starts at boot. Active means it is running right now. They are independent — systemctl enable --now does both, which is usually what people intend.
What does active (exited) mean?
The service ran, completed successfully, and exited. This is normal for oneshot units that perform a task rather than staying resident, such as applying firewall rules at boot.
Why does systemctl fail inside a Docker container?
Most containers run a single process as PID 1 with no init system, so there is no systemd to talk to. Use ps inside the container, and manage lifecycle from the host with docker ps and the orchestrator.
How do I see which services use the most resources?
systemd-cgtop shows CPU and memory per unit using cgroup accounting, which correctly attributes usage across a service’s forked children. For boot time specifically, use systemd-analyze blame.