Toolmingo
Guides12 min read

Linux Process Management: ps, kill, top, and Job Control

A complete guide to Linux process management — list, inspect, kill, background, and monitor processes using ps, kill, top, htop, jobs, nohup, systemctl, and /proc. Copy-ready commands.

Every Linux system is running dozens of processes at any moment. Knowing how to list them, inspect them, and kill them — without breaking anything else — is an essential sysadmin and developer skill. This guide covers everything from basic ps to job control, signals, systemctl, and /proc.

Quick reference

Task Command
List all running processes ps aux
Show process tree ps auxf or pstree -p
Find process by name pgrep nginx or ps aux | grep nginx
Kill by PID kill 1234
Force-kill by PID kill -9 1234
Kill by name pkill nginx
Interactive process monitor top or htop
Run in background command &
Send running process to background Ctrl+Z, then bg
Bring background job to foreground fg %1
List background jobs jobs
Keep running after logout nohup command &
Show systemd service status systemctl status nginx
Restart a service sudo systemctl restart nginx
View process files/connections lsof -p 1234

Listing processes with ps

ps (process status) is the standard tool for inspecting processes.

# All processes, BSD-style (most common)
ps aux

# COLUMNS: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# USER = owner, PID = process ID, STAT = state (S=sleeping, R=running, Z=zombie)

# All processes, UNIX-style
ps -ef

# Process tree (shows parent/child relationships)
ps auxf

# Processes for a specific user
ps -u www-data

# Show specific columns
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -20

# Find process by name (case-insensitive)
ps aux | grep -i nginx

# Show a specific PID
ps -p 1234 -o pid,ppid,cmd,stat,%cpu,%mem

Process states (STAT column)

Code Meaning
R Running or runnable
S Interruptible sleep (waiting for event)
D Uninterruptible sleep (usually I/O)
T Stopped (by signal or job control)
Z Zombie (finished but not reaped by parent)
< High priority
N Low priority (nice > 0)
s Session leader
l Multi-threaded
+ In foreground process group

Finding processes

# Find PID by name
pgrep nginx          # returns PID(s)
pgrep -l nginx       # returns PID and name
pgrep -a nginx       # returns PID and full command
pgrep -u www-data    # all processes by user

# Find with details
pidof nginx          # PIDs of exact process name

# Full-text search across all processes
ps aux | grep '[n]ginx'   # the [n] trick avoids matching grep itself

# Find what's using a port
ss -tlnp | grep :80
lsof -i :80
fuser 80/tcp         # just the PID

# Find what process has a file open
lsof /var/log/nginx/access.log

# Find what files a process has open
lsof -p 1234

Sending signals with kill

kill sends a signal to a process — it does not have to mean "terminate."

# Send default signal (SIGTERM = graceful shutdown)
kill 1234

# Force kill (SIGKILL — cannot be caught or ignored)
kill -9 1234
kill -KILL 1234      # same thing

# Reload config without restart (SIGHUP)
kill -HUP 1234
kill -1 1234         # same thing

# Pause a process (SIGSTOP)
kill -STOP 1234

# Resume a paused process (SIGCONT)
kill -CONT 1234

# Kill by name
pkill nginx           # SIGTERM to all matching
pkill -9 nginx        # SIGKILL to all matching
pkill -HUP nginx      # SIGHUP to all matching
pkill -u www-data     # kill all processes by user

# Kill process group
kill -9 -1234         # negative PID = process group

Common signals

Signal Number Default action When to use
SIGTERM 15 Terminate (graceful) Default — always try this first
SIGKILL 9 Terminate (forced) Process won't respond to SIGTERM
SIGHUP 1 Terminate (or reload) Reload config (nginx, sshd, etc.)
SIGINT 2 Terminate Same as Ctrl+C
SIGQUIT 3 Core dump Debug crash
SIGSTOP 19 Stop Pause process
SIGCONT 18 Continue Resume paused process
SIGUSR1 10 User-defined App-specific (e.g., reopen log files)
SIGUSR2 12 User-defined App-specific

Rule: Always try kill PID (SIGTERM) first. Give the process a few seconds to clean up. Only use kill -9 if it doesn't stop.


Interactive monitoring with top

top

Inside top:

Key Action
q Quit
k Kill (prompts for PID then signal)
r Renice (change priority)
M Sort by memory
P Sort by CPU
T Sort by time
u Filter by user
1 Show individual CPU cores
H Show threads
f Fields management
d Change refresh interval
W Save settings

Useful top one-liners:

# Run top in batch mode (non-interactive, for scripting)
top -b -n 1 | head -20

# Show only one user's processes
top -u www-data

# Run for N iterations then exit
top -b -n 3        # 3 snapshots, good for scripts

htop

htop is top with a better interface. Install with apt install htop or yum install htop.

htop                      # interactive
htop -u www-data          # filter by user
htop -p 1234,5678         # watch specific PIDs
htop -d 10                # 1-second refresh (delay in 10ths)

Job control

Job control lets you run multiple commands in one terminal — pause, background, and foreground them.

# Start a command in the background
sleep 300 &
# [1] 12345   ← job number and PID

# List background jobs
jobs
# [1]+  Running    sleep 300 &
# [2]-  Stopped    vim file.txt

# Bring job 1 to foreground
fg %1

# Send foreground job to background
# 1. Press Ctrl+Z to pause it
# 2. Run:
bg %1

# Wait for all background jobs to finish
wait

# Disown a job (detach from terminal — won't die on logout)
disown %1

# Run something that continues after logout
nohup long-running-command > output.log 2>&1 &

Job spec syntax

Spec Refers to
%1 Job number 1
%+ Current job (most recently stopped/backgrounded)
%- Previous job
%nginx Job whose command starts with "nginx"
%?log Job whose command contains "log"

Running processes that survive logout

# nohup: ignore SIGHUP (terminal close), redirect output
nohup python3 server.py > server.log 2>&1 &

# Check it's still running
jobs
ps aux | grep server.py

# screen: full terminal multiplexer
screen -S mysession           # start named session
screen -ls                    # list sessions
screen -r mysession           # reattach
# Inside screen: Ctrl+A then D to detach

# tmux (preferred over screen)
tmux new -s mysession
tmux ls
tmux attach -t mysession
# Inside tmux: Ctrl+B then D to detach

Process priority with nice and renice

Priority ranges from -20 (highest) to 19 (lowest). Default is 0. Regular users can only increase nice value (lower priority). Root can set any value.

# Start a process with lower priority (won't compete with system processes)
nice -n 10 python3 heavy-script.py

# Start with highest priority (root only)
sudo nice -n -20 critical-task

# Change priority of a running process
renice 15 -p 1234             # lower priority by PID
sudo renice -10 -p 1234       # raise priority (root only)
renice 5 -u www-data          # change all www-data processes

Systemd and systemctl

Most modern Linux distros use systemd. systemctl manages services (daemons).

# Service lifecycle
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx         # reload config without full restart

# Enable/disable on boot
sudo systemctl enable nginx
sudo systemctl disable nginx
sudo systemctl enable --now nginx   # enable AND start immediately

# Status and logs
systemctl status nginx
journalctl -u nginx                 # all logs for nginx
journalctl -u nginx -f              # follow (like tail -f)
journalctl -u nginx --since today
journalctl -u nginx --since "2026-07-14 10:00" --until "2026-07-14 11:00"

# List services
systemctl list-units --type=service
systemctl list-units --type=service --state=running
systemctl list-units --type=service --state=failed

# Check if service is active/enabled
systemctl is-active nginx
systemctl is-enabled nginx

# View unit file
systemctl cat nginx
sudo systemctl edit nginx           # override unit file

Writing a simple systemd service

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/server.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload        # after creating/editing unit file
sudo systemctl enable --now myapp

The /proc filesystem

/proc is a virtual filesystem exposing kernel and process information.

# Process-specific info (replace 1234 with actual PID)
cat /proc/1234/cmdline | tr '\0' ' '    # full command line
cat /proc/1234/status                   # process status and memory
cat /proc/1234/fd/ | ls -la            # open file descriptors
cat /proc/1234/net/tcp                  # network connections
cat /proc/1234/maps                     # memory map
cat /proc/1234/environ | tr '\0' '\n'  # environment variables

# System-wide info
cat /proc/cpuinfo        # CPU details
cat /proc/meminfo        # memory usage
cat /proc/uptime         # system uptime in seconds
cat /proc/loadavg        # load average (1, 5, 15 min + running/total processes)
cat /proc/version        # kernel version

Resource monitoring

# CPU and memory overview
free -h                  # memory usage (human readable)
vmstat 1 5               # virtual memory stats (1s interval, 5 times)
mpstat 1 5               # per-CPU stats (needs sysstat)
iostat 1 5               # I/O stats

# Disk I/O by process
iotop -o                 # only processes doing I/O (needs root)
iotop -a                 # accumulated I/O

# Network bandwidth by process
nethogs eth0             # bandwidth per process

# Load average
uptime
# 14:23:01 up 5 days, load average: 0.15, 0.12, 0.10
# 1-min, 5-min, 15-min averages. Rule of thumb: < CPU count = OK

# Find memory hogs
ps aux --sort=-%mem | head -10

# Find CPU hogs
ps aux --sort=-%cpu | head -10

# Watch a command every 2 seconds
watch -n 2 'ps aux --sort=-%cpu | head -10'

Practical patterns

Pattern 1: Safely stop a stubborn process

PID=$(pgrep -f "myapp.py")
echo "Found PID: $PID"

# Try graceful first
kill "$PID"
sleep 3

# Check if still running
if kill -0 "$PID" 2>/dev/null; then
  echo "Process still running, force-killing..."
  kill -9 "$PID"
else
  echo "Process stopped cleanly."
fi

Pattern 2: Run a script in the background, save PID

#!/bin/bash
nohup python3 worker.py > /var/log/worker.log 2>&1 &
echo $! > /var/run/worker.pid
echo "Started with PID $(cat /var/run/worker.pid)"

# Later, to stop it:
kill "$(cat /var/run/worker.pid)"

Pattern 3: Wait for a port to be available

wait_for_port() {
  local port=$1
  local retries=30
  while ! ss -tlnp | grep -q ":${port} "; do
    ((retries--)) || { echo "Timeout waiting for port $port"; return 1; }
    echo "Waiting for port $port..."
    sleep 1
  done
  echo "Port $port is ready."
}

wait_for_port 5432    # wait for PostgreSQL

Pattern 4: Monitor a process and restart on crash

#!/bin/bash
# Simple process watchdog (prefer systemd Restart= in production)
while true; do
  if ! pgrep -f "myapp.py" > /dev/null; then
    echo "$(date): myapp.py not running, restarting..."
    nohup python3 /opt/myapp/myapp.py >> /var/log/myapp.log 2>&1 &
  fi
  sleep 10
done

Common mistakes

Mistake Problem Fix
Going straight to kill -9 Process can't clean up (open files, DB connections left open) Always try kill PID first, wait, then -9
Killing by name with pkill carelessly May kill unintended processes with similar names Check with pgrep -l name before running pkill
ps aux | grep name matches itself The grep process shows up in results Use pgrep -a name or grep '[n]ame' pattern
Running heavy tasks at default priority Competes with interactive processes Use nice -n 10 command
Not using nohup for background jobs Process dies when terminal closes nohup command > output.log 2>&1 &
Assuming PID won't change PID can be reused after process dies Use pidfiles or re-run pgrep
Managing services with raw kill instead of systemctl Service won't auto-restart, logs scattered Use systemctl stop/restart on systemd systems

ps vs top vs htop vs systemctl

Tool Best for
ps aux Snapshot, scripting, grep-friendly
ps auxf Seeing process tree relationships
top Live monitoring, available everywhere
htop Live monitoring with better UX (color, mouse, tree view)
lsof -p PID What files/connections does this process have?
systemctl status Status of a named service with recent logs
journalctl -u service Full log history for a systemd service
pgrep / pkill Scripted find/kill by name

FAQ

Q: What's the difference between kill -9 and kill -15?
-15 (SIGTERM) is a polite request — the process can catch it and clean up. -9 (SIGKILL) goes directly to the kernel; the process never sees it and cannot block it. Always use SIGTERM first.

Q: My process shows as D state (uninterruptible sleep). How do I kill it?
You often can't — it's waiting on I/O (usually a stuck NFS mount or failing disk). Even kill -9 won't work because the process is in kernel space. Fix the underlying I/O problem (unmount the NFS share, check disk health). A reboot is sometimes the only option.

Q: What is a zombie process and should I worry about it?
A zombie (state Z) is a process that has finished but whose parent hasn't called wait() to read its exit status. A few zombies are harmless. Many zombies usually indicate a buggy parent process. Killing the parent (or waiting for it to call wait()) cleans them up.

Q: How do I find which process is using the most memory?
ps aux --sort=-%mem | head -10 gives a quick snapshot. For ongoing monitoring, htop sorted by MEM% is easiest. For RSS vs VSZ: RSS is actual physical RAM used; VSZ includes all virtual memory (often inflated by shared libraries).

Q: How do I run a cron job so it stays running even if it crashes?
Use systemd with Restart=on-failure in the unit file — that's the proper solution. Alternatively, combine cron with a lockfile check. For long-running daemons, systemd is always preferable to raw cron.

Q: What's the difference between kill -HUP and systemctl reload?
kill -HUP PID sends SIGHUP directly to a specific PID. systemctl reload nginx also sends SIGHUP but only if the unit file defines ExecReload=. systemctl reload is safer because systemd tracks the outcome and updates service state; kill -HUP is a fire-and-forget signal.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools