>
Every Linux system runs dozens of processes simultaneously—some visible, most hidden. To keep your system stable and performant, you need to monitor what's running and terminate what's broken. The ps, top, and kill commands, combined with systemd, give you complete control over process behavior. Here's how to use them like a pro.
A process is an instance of a running program with its own memory space, file descriptors, and system resources. Every process has a unique Process ID (PID), a parent process ID (PPID), and ownership (user/group). The kernel scheduler decides which process runs at any given moment, managing CPU time across all active processes.
Why does this matter? A runaway process can consume 100% CPU. A memory leak can exhaust RAM. A zombie process can block system resources. Process management is how you prevent chaos. Let's start with viewing what's running.
ps Command: Static Process SnapshotThe ps command displays a static snapshot of running processes. It's lightweight, scriptable, and perfect for finding specific processes or generating reports.
ps aux
This shows every process on the system with full details:
Finding a specific process is crucial when you need to manage it:
ps aux | grep nginx
This searches for all processes containing "nginx". Be careful—the grep command itself will appear in the results. A better approach uses the -f flag with pgrep:
pgrep -a nginx
This shows PIDs and full command lines for all nginx processes without the grep command appearing.
Understanding parent-child relationships helps when troubleshooting. View the process tree:
ps aux --forest
Or use the dedicated tree viewer:
pstree -p
The -p flag adds PIDs, making it easier to identify specific processes in the hierarchy.
top Command: Real-Time MonitoringWhile ps gives you a snapshot, top provides real-time monitoring. It updates every second (by default) and shows which processes are consuming the most resources right now.
top
You'll see a summary at the top:
Below that, you see individual processes sorted by CPU usage by default. High load averages (above your CPU count) mean the system is overloaded. Zombie processes that don't disappear indicate a parent process isn't reaping them properly.
Once top is running, you can interact with it:
For scripts and monitoring systems, use batch mode:
top -b -n 1 | head -20
The -b flag runs non-interactively, and -n 1 limits it to one iteration. Pipe to head to show just the summary, or capture the output for analysis.
kill Command: Terminating ProcessesSometimes processes must be stopped. The kill command sends signals to processes. It's not actually killing—it's sending a message, and the process decides how to respond.
Linux defines about 30 signals. The most important ones:
First, find the PID:
pgrep -a postgres
Then send a signal. By default, kill sends SIGTERM:
kill 2451
This is polite—the process gets a chance to exit cleanly. If it doesn't respond after a few seconds, escalate:
kill -9 2451
The -9 sends SIGKILL, which immediately terminates the process. Use this only when SIGTERM fails.
To kill all processes matching a name, use pkill:
pkill -f "python script.py"
The -f flag matches against the full command line, not just the process name. This is more precise than grepping and parsing PIDs manually.
Modern Linux distributions use systemd as their init system. It manages the boot process, system services, and dependencies between services. Understanding systemd is essential for production work.
In systemd terminology, a "unit" is any resource it manages—usually a service. A service unit represents a long-running process. Unit files are stored in /etc/systemd/system/ or /usr/lib/systemd/system/.
Here's a simple unit file for a hypothetical web application:
[Unit]
Description=My Web App
After=network.target
[Service]
Type=simple
User=webapp
ExecStart=/opt/myapp/bin/server
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Key sections:
Manage services with systemctl:
systemctl start nginx # Start the service
systemctl stop nginx # Stop the service
systemctl restart nginx # Restart the service
systemctl reload nginx # Reload config (no downtime)
systemctl enable nginx # Auto-start on boot
systemctl disable nginx # Don't auto-start
systemctl status nginx # Show current status
systemctl is-active nginx # Check if running (scriptable)
To see all services and their status:
systemctl list-units --type=service
systemd logs go to the journal. View them with journalctl:
journalctl -u nginx # Show nginx logs
journalctl -u nginx -f # Follow logs (like tail -f)
journalctl -u nginx --since "1 hour ago" # Last hour
journalctl -u nginx -n 50 # Last 50 lines
The journal is searchable and structured, making debugging much easier than traditional syslog.
systemd respects dependencies. If a service requires another service to be running first, systemd handles the startup order. Define dependencies in the unit file:
[Unit]
After=postgresql.service
Wants=redis.service
After means "don't start until this is running." Wants means "start this if possible, but don't fail if it's unavailable."
Let's use everything together. Your application is using 95% CPU:
Step 1: Identify the culprit
top
You see java at the top, consuming 95% CPU. Press shift+m to see memory too. Note the PID.
Step 2: Get details
ps -p 4521 -o pid,ppid,cmd,etime
This shows the full command, parent PID, and elapsed time. You recognize it as the application that crashed.
Step 3: Stop it gracefully
kill 4521
Wait 5 seconds.
Step 4: Force kill if needed
ps -p 4521 && kill -9 4521
The ps -p 4521 checks if it's still running. If yes, kill it forcefully.
Step 5: Restart via systemd
systemctl restart myapp
systemd restarts it according to its configuration, handling dependencies and logging.
Step 6: Check logs