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.
Every process has a unique Process ID (PID). The kernel tracks all processes and their state.
| Concept | Description |
|---|---|
| PID | Process ID — unique integer assigned by the kernel |
| PPID | Parent Process ID — the process that spawned this one |
| UID/GID | The user/group identity the process runs as |
| Priority | Nice value (-20 to +19); lower = higher priority |
| State | Current execution state (see below) |
| State | Code | Meaning |
|---|---|---|
| Running | R | Currently executing or ready to run |
| Sleeping | S | Interruptible sleep — waiting for event (I/O, signal) |
| Disk Sleep | D | Uninterruptible sleep — waiting for disk I/O (cannot be killed) |
| Zombie | Z | Process finished but parent hasn't read exit status yet |
| Stopped | T | Process paused (Ctrl+Z or SIGSTOP) |
| Traced | t | Being debugged by debugger (ptrace) |
| Idle | I | Kernel 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
# 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
# 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 - 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
| Key | Action |
|---|---|
| q | Quit top |
| k | Kill a process (prompts for PID and signal) |
| r | Renice (change priority) of a process |
| P | Sort by CPU usage (default) |
| M | Sort by memory usage |
| T | Sort by running time |
| N | Sort by PID |
| 1 | Toggle per-CPU display |
| m | Toggle memory display mode |
| t | Toggle CPU display mode |
| u | Filter by username |
| f | Field management (add/remove columns) |
| H | Toggle threads view |
| Space | Refresh immediately |
# 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
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
| Signal | Number | Meaning | Use When |
|---|---|---|---|
| SIGHUP | 1 | Hang up / reload | Reload config without restart |
| SIGINT | 2 | Interrupt | Ctrl+C — user wants to stop |
| SIGKILL | 9 | Kill (force) | Process won't die otherwise |
| SIGTERM | 15 | Terminate (graceful) | Normal shutdown request |
| SIGSTOP | 19 | Stop (pause) | Suspend a process |
| SIGCONT | 18 | Continue | Resume a stopped process |
| SIGUSR1 | 10 | User-defined 1 | App-specific (e.g., reopen logs) |
| SIGUSR2 | 12 | User-defined 2 | App-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
# 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
# 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
# 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
# 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
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)
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
# 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
| Feature | Daemon | Foreground Process |
|---|---|---|
| TTY | None (shows as ? in ps) | Attached to terminal (pts/0, etc.) |
| Startup | System boot via systemd/init | Manually by user or script |
| Life span | Runs continuously | Until user stops or closes terminal |
| Examples | nginx, sshd, cron, mysql | vim, bash, top, your scripts |
| Config | Unit files in /etc/systemd/ | N/A |
| Signals | SIGHUP often reloads config | SIGINT (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