🏠 Home / Hub

Linux 04 — Process Management

A process is a running instance of a program. Linux is a multi-process operating system — hundreds of processes run simultaneously. Understanding how to inspect, control, and manage them is a core sysadmin skill.

1. What is a Process?

Every process has a unique Process ID (PID). The kernel tracks all processes and their state.

ConceptDescription
PIDProcess ID — unique integer assigned by the kernel
PPIDParent Process ID — the process that spawned this one
UID/GIDThe user/group identity the process runs as
PriorityNice value (-20 to +19); lower = higher priority
StateCurrent execution state (see below)

Process States

StateCodeMeaning
RunningRCurrently executing or ready to run
SleepingSInterruptible sleep — waiting for event (I/O, signal)
Disk SleepDUninterruptible sleep — waiting for disk I/O (cannot be killed)
ZombieZProcess finished but parent hasn't read exit status yet
StoppedTProcess paused (Ctrl+Z or SIGSTOP)
TracedtBeing debugged by debugger (ptrace)
IdleIKernel thread in idle state
# The process hierarchy
# PID 1: init/systemd (parent of everything)
# All processes form a tree

$ pstree                          # show process tree
$ pstree -p                       # include PIDs
$ pstree -u                       # include username
$ pstree alice                    # tree for alice's processes

2. ps — Process Status Snapshot

# ps shows a SNAPSHOT of processes at that moment (not live)

# Most common: BSD syntax (no dash)
$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY    STAT START   TIME COMMAND
root         1  0.0  0.1  16956  9540 ?      Ss   Jun14   0:01 /sbin/init
alice     1234  0.1  0.5 125480 40960 pts/0  S    10:00   0:05 bash
nginx    23456  0.0  0.2  55024 16384 ?      S    Jun14   2:10 nginx: worker

# Flags: a=all users, u=user-oriented format, x=include processes without terminal

# Unix syntax (with dash)
$ ps -ef                          # all processes, full format
$ ps -aux                         # same as ps aux (mostly)
$ ps -u alice                     # processes owned by alice
$ ps -p 1234                      # specific PID
$ ps -C nginx                     # by command name

# Useful ps combinations
$ ps aux | grep nginx             # find nginx processes
$ ps aux | grep -v grep | grep nginx  # exclude the grep itself
$ ps aux --sort=-%cpu | head -10  # top 10 CPU consumers
$ ps aux --sort=-%mem | head -10  # top 10 memory consumers
$ ps aux --sort=pid               # sorted by PID

# Process tree
$ ps axf                          # ASCII art process tree
$ ps --forest -o pid,ppid,user,cmd  # tree with custom columns

# Custom output format
$ ps -eo pid,user,pcpu,pmem,cmd --sort=-pcpu | head -20
# Columns: e=all, o=output format, pid, user, %cpu, %mem, command

# Long listing of a specific process
$ ps -fp 1234
UID        PID  PPID  C STIME TTY          TIME CMD
root      1234  1230  0 10:00 pts/0    00:00:00 bash

3. top — Live Process Viewer

# top updates every 3 seconds by default
$ top
$ top -d 1          # refresh every 1 second
$ top -p 1234       # monitor specific PID
$ top -u alice      # show only alice's processes
$ top -b -n 3       # batch mode, 3 iterations (for scripting)
$ top -b -n 1 > processes.txt   # save snapshot to file

top Header Explained

top - 10:23:45 up 5 days, 2:14,  2 users,  load average: 0.52, 0.58, 0.65
Tasks: 198 total,   1 running, 197 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.1 us,  0.5 sy,  0.0 ni, 97.0 id,  0.3 wa,  0.0 hi,  0.1 si
MiB Mem :  16384.0 total,   4096.0 free,   8192.0 used,   4096.0 buff/cache
MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   7680.0 avail Mem

# Load average: 0.52, 0.58, 0.65
# Three numbers: 1-min, 5-min, 15-min average
# On a 4-core system: 4.0 = fully loaded, >4.0 = overloaded

# %Cpu line:
# us = user space, sy = system/kernel, ni = nice (low priority)
# id = idle, wa = I/O wait, hi = hardware IRQ, si = software IRQ

top Interactive Keys

KeyAction
qQuit top
kKill a process (prompts for PID and signal)
rRenice (change priority) of a process
PSort by CPU usage (default)
MSort by memory usage
TSort by running time
NSort by PID
1Toggle per-CPU display
mToggle memory display mode
tToggle CPU display mode
uFilter by username
fField management (add/remove columns)
HToggle threads view
SpaceRefresh immediately

4. htop — Enhanced Interactive Process Viewer

# Install htop
$ sudo apt install htop         # Debian/Ubuntu
$ sudo yum install htop         # CentOS/RHEL

$ htop                          # launch
$ htop -u alice                 # show only alice's processes
$ htop -p 1234,5678             # monitor specific PIDs

# htop advantages over top:
# - Color-coded CPU/memory bars
# - Mouse support (click to select)
# - Easier to kill processes (F9)
# - Can scroll horizontally to see full command
# - Tree view (F5)
# - Search (F3)
# - Filter (F4)

# htop key bindings
# F1         Help
# F2         Setup/configuration
# F3         Search (find process by name)
# F4         Filter processes
# F5         Toggle tree view
# F6         Sort by column
# F7/F8      Lower/raise process priority
# F9         Kill process (select signal)
# F10        Quit

5. kill — Send Signals to Processes

Signals are messages sent to processes. Every signal has a number and a name. Most users only need SIGTERM and SIGKILL.

# List all available signals
$ kill -l

# Most important signals
$ kill -15 1234      # SIGTERM — graceful shutdown (default if no signal given)
$ kill 1234          # SIGTERM (same — 15 is default)
$ kill -9 1234       # SIGKILL — force kill (cannot be ignored or caught)
$ kill -1 1234       # SIGHUP — hang up (often causes daemon to reload config)
$ kill -2 1234       # SIGINT — interrupt (same as Ctrl+C)
$ kill -19 1234      # SIGSTOP — pause process (cannot be caught)
$ kill -18 1234      # SIGCONT — continue a stopped process
$ kill -3 1234       # SIGQUIT — quit with core dump
SignalNumberMeaningUse When
SIGHUP1Hang up / reloadReload config without restart
SIGINT2InterruptCtrl+C — user wants to stop
SIGKILL9Kill (force)Process won't die otherwise
SIGTERM15Terminate (graceful)Normal shutdown request
SIGSTOP19Stop (pause)Suspend a process
SIGCONT18ContinueResume a stopped process
SIGUSR110User-defined 1App-specific (e.g., reopen logs)
SIGUSR212User-defined 2App-specific action
# Kill by name
$ killall nginx                  # kill all processes named nginx
$ killall -9 python3             # force kill all python3 processes
$ killall -u alice               # kill all processes owned by alice

# pkill — kill by pattern
$ pkill nginx                    # kill processes matching name
$ pkill -f "python manage.py"    # -f: match against full command line
$ pkill -9 -u alice              # force kill all alice's processes
$ pkill -SIGHUP nginx            # send reload signal to nginx

# Kill multiple processes
$ kill -9 1234 5678 9012         # kill multiple PIDs at once
$ kill -9 $(pgrep python3)       # kill all python3 processes
Best practice: Always try SIGTERM (15) first. Give the process a few seconds to shut down gracefully. Only use SIGKILL (9) if it won't stop — SIGKILL doesn't allow cleanup.

6. Jobs — Foreground and Background

# Run a command in the background
$ sleep 60 &                     # run sleep in background; shell prints [1] PID
[1] 1234

# List background jobs
$ jobs                           # show all jobs
$ jobs -l                        # show with PIDs
[1]+ 1234 Running    sleep 60 &
[2]- 5678 Stopped    vim file.txt

# fg — bring background job to foreground
$ fg                             # bring most recent job to foreground
$ fg 1                           # bring job #1 to foreground
$ fg %1                          # same (% prefix for job number)

# bg — resume a stopped job in background
$ bg                             # resume most recent stopped job
$ bg 2                           # resume job #2 in background

# Suspend foreground process
# Ctrl+Z while process is running → sends SIGSTOP
$ vim file.txt
^Z
[1]+  Stopped                 vim file.txt
$ bg                             # resume vim in background (won't work well for vim)

# Disown — keep job running after logout
$ long_script.sh &
$ disown %1                      # remove from job table (survives logout)
$ disown -h %1                   # mark to not receive SIGHUP on logout

7. nohup — Survive Shell Logout

# nohup runs command immune to hangup signal
# Output goes to nohup.out by default

$ nohup ./long_process.sh &
nohup: ignoring input and appending output to 'nohup.out'
[1] 1234

$ nohup python3 server.py > server.log 2>&1 &  # redirect output
$ nohup bash -c "while true; do check_health.sh; sleep 60; done" &

# Better alternative: use screen or tmux for interactive sessions
$ screen -S mysession             # start named screen session
$ screen -ls                      # list sessions
$ screen -r mysession             # reattach to session

$ tmux new -s myserver            # start tmux session
$ tmux ls                         # list sessions
$ tmux attach -t myserver         # reattach

8. Process Priority — nice and renice

# Nice value ranges: -20 (highest priority) to +19 (lowest priority)
# Default nice value for user processes: 0
# Regular users can only INCREASE nice value (lower priority)
# Root can set negative nice (higher than default)

# Launch with nice value
$ nice -n 10 ./backup.sh                # run at lower priority (nice=10)
$ nice -n -5 ./critical_task.sh         # higher priority (root only)
$ sudo nice -n -20 ./realtime_proc      # maximum priority (root only)

# Change priority of running process
$ renice 15 -p 1234                     # set PID 1234 to nice=15
$ renice -5 -p 1234                     # increase priority (root only)
$ renice 10 -u alice                    # renice all of alice's processes
$ renice 5 -g mygroup                   # renice by process group

# View priority in ps and top
$ ps -eo pid,ni,pri,cmd | head -20      # ni=nice, pri=priority

9. Finding Processes — pgrep, pidof, lsof

# pgrep — find PID by name/pattern
$ pgrep nginx                    # PIDs of nginx processes
$ pgrep -l nginx                 # PID + name
$ pgrep -a nginx                 # PID + full command line
$ pgrep -u alice                 # all PIDs owned by alice
$ pgrep -f "python manage.py"    # match full command line
$ pgrep -x bash                  # exact match (no substring)

# pidof — find PID of exact program name
$ pidof nginx
1234 1235 1236
$ pidof -s nginx                 # single PID only
$ pidof sshd

# lsof — list open files (everything is a file on Linux)
$ lsof                           # ALL open files (very long output)
$ lsof -p 1234                   # files opened by specific PID
$ lsof -u alice                  # files opened by user alice
$ lsof /var/log/nginx/access.log # who has this file open?
$ lsof -i                        # all network connections
$ lsof -i :80                    # processes listening on port 80
$ lsof -i :443                   # processes on port 443
$ lsof -i TCP:22                 # TCP connections on port 22
$ lsof -i -n -P                  # all network, no hostname/port lookup
$ lsof -i 4                      # IPv4 only
$ lsof +D /var/www/              # all files under this directory

10. /proc Filesystem

The /proc virtual filesystem exposes kernel data structures as files. It is the foundation of most process monitoring tools.

# Per-process information
$ ls /proc/1234/
cmdline  cwd  environ  exe  fd/  maps  mem  net/  root  stat  status

$ cat /proc/1234/status             # human-readable process info
$ cat /proc/1234/cmdline            # command that started the process
$ ls -la /proc/1234/exe             # symlink to executable
$ ls -la /proc/1234/fd/             # open file descriptors
$ cat /proc/1234/maps               # memory mappings

# System-wide /proc files
$ cat /proc/cpuinfo                 # CPU model, cores, flags
$ cat /proc/meminfo                 # detailed memory information
$ cat /proc/uptime                  # system uptime in seconds
$ cat /proc/loadavg                 # load averages (1, 5, 15 min)
$ cat /proc/version                 # kernel version
$ cat /proc/net/tcp                 # TCP connections table
$ cat /proc/mounts                  # currently mounted filesystems
$ cat /proc/filesystems             # supported filesystem types
$ cat /proc/interrupts              # hardware interrupt counters

# Useful reads from /proc
$ cat /proc/sys/kernel/hostname     # system hostname
$ cat /proc/sys/vm/swappiness       # swap usage tendency (0-100)
$ echo 10 > /proc/sys/vm/swappiness # change swappiness (as root)

11. systemctl — Managing Services

systemd is the init system on most modern Linux distributions. systemctl is its command-line interface.

# Service control
$ systemctl start nginx             # start a service
$ systemctl stop nginx              # stop a service
$ systemctl restart nginx           # stop then start
$ systemctl reload nginx            # reload config (no downtime if supported)
$ systemctl enable nginx            # start automatically on boot
$ systemctl disable nginx           # don't start on boot
$ systemctl mask nginx              # prevent from being started (even manually)
$ systemctl unmask nginx            # reverse mask

# Service status
$ systemctl status nginx            # detailed service status
$ systemctl is-active nginx         # just "active" or "inactive"
$ systemctl is-enabled nginx        # "enabled" or "disabled"
$ systemctl is-failed nginx         # check if service failed

# List services
$ systemctl list-units              # all loaded units
$ systemctl list-units --type=service  # services only
$ systemctl list-units --state=failed  # only failed services
$ systemctl list-unit-files         # all unit files and their state
$ systemctl list-unit-files --type=service --state=enabled  # enabled services

# System control
$ systemctl daemon-reload           # reload unit files after editing
$ systemctl reboot                  # reboot system
$ systemctl poweroff                # power off
$ systemctl suspend                 # suspend to RAM
$ systemctl hibernate               # suspend to disk

# Create a simple service unit
$ sudo vim /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myappuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/start.sh
ExecStop=/opt/myapp/stop.sh
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now myapp    # enable and start immediately

12. journalctl — Reading systemd Logs

# journalctl reads from the systemd journal (binary log database)

# Basic usage
$ journalctl                         # all journal entries (oldest first)
$ journalctl -r                      # reversed (newest first)
$ journalctl -n 50                   # last 50 lines
$ journalctl -f                      # follow (like tail -f)

# Filter by service/unit
$ journalctl -u nginx                # nginx logs only
$ journalctl -u nginx -u php-fpm     # multiple services
$ journalctl -u nginx -f             # follow nginx logs
$ journalctl -u nginx -n 100 -r      # last 100 nginx entries, newest first

# Filter by time
$ journalctl --since "2024-06-15"
$ journalctl --since "2024-06-15 10:00:00"
$ journalctl --since "1 hour ago"
$ journalctl --since yesterday
$ journalctl --until "2024-06-15 12:00:00"
$ journalctl --since "2024-06-15" --until "2024-06-16"

# Filter by priority
$ journalctl -p err                  # errors and worse
$ journalctl -p warning              # warnings and worse
$ journalctl -p "0..3"               # emerg through error
# Priorities: 0=emerg, 1=alert, 2=crit, 3=err, 4=warning, 5=notice, 6=info, 7=debug

# Other options
$ journalctl -k                      # kernel messages only (like dmesg)
$ journalctl -b                      # current boot only
$ journalctl -b -1                   # previous boot
$ journalctl --disk-usage            # how much space journal is using
$ journalctl --vacuum-size=500M      # trim journal to 500MB
$ journalctl -o json-pretty          # JSON output format
$ journalctl -u nginx | grep "error" # combine with grep

13. Daemons vs Foreground Processes

FeatureDaemonForeground Process
TTYNone (shows as ? in ps)Attached to terminal (pts/0, etc.)
StartupSystem boot via systemd/initManually by user or script
Life spanRuns continuouslyUntil user stops or closes terminal
Examplesnginx, sshd, cron, mysqlvim, bash, top, your scripts
ConfigUnit files in /etc/systemd/N/A
SignalsSIGHUP often reloads configSIGINT (Ctrl+C) stops it
# Check if a process is a daemon (no TTY)
$ ps aux | awk '$7 == "?" {print $11, $1, $2}'

# Common daemons on a Linux server
$ systemctl list-units --type=service --state=running
# sshd.service     — SSH daemon
# nginx.service    — web server
# mysql.service    — database
# cron.service     — scheduled jobs
# rsyslog.service  — logging
# NetworkManager   — network management

📌 Study Checklist