RED HAT ENTERPRISE LINUX
Managing Processes
Investigate, Control, and Terminate Running Processes
CIS126RH | RHEL System Administration 1 Mesa Community College
Welcome to this essential module on process management in Red Hat Enterprise Linux. A process is simply a running instance of a program. Every command you execute, every service running on your server, every application - they're all processes. Understanding how to view, monitor, and control processes is fundamental to Linux system administration. You need these skills to troubleshoot performance issues, manage system resources, stop misbehaving applications, and understand what your system is doing at any moment. In this module, we'll cover how to view processes with commands like ps and top, understand process states and priorities, send signals to control processes, and manage foreground and background jobs. These skills are essential for the RHCSA exam and daily administration work.
Learning Objectives
1
View and monitor processes
Use ps, top, and other tools to examine running processes
2
Understand process states
Know what Running, Sleeping, Stopped, and Zombie mean
3
Send signals to processes
Use kill, killall, and pkill to control and terminate processes
4
Manage job control and priority
Work with foreground/background jobs and adjust process priority
We have four main learning objectives for this module. First, we'll learn to view and monitor processes using essential commands like ps for snapshots and top for real-time monitoring. You'll understand the information these tools provide and how to filter for what you need. Second, we'll understand process states - what it means when a process is Running, Sleeping, Stopped, or in the dreaded Zombie state. This helps you understand what your processes are doing and identify problems. Third, we'll master sending signals to processes. Signals are how you communicate with processes - asking them to terminate, forcing them to stop, or triggering other behaviors. The kill command family is essential for process control. Fourth, we'll manage job control and process priority. You'll learn to run processes in the background, bring them to the foreground, and adjust their priority to manage system resources effectively.
What is a Process ?
A process is a running instance of a program. Each process has a unique Process ID (PID), its own memory space, and associated resources.
PID
Unique numeric identifier assigned to each process by the kernel
PPID
Parent Process ID - the process that spawned this one
State
Current status: Running, Sleeping, Stopped, or Zombie
Priority
Nice value determining CPU scheduling preference
Process 1: The first process (PID 1) is systemd on RHEL. It's the ancestor of all other processes and the init system.
Let's understand what a process actually is. When you run a program - whether it's ls, vim, a web server, or anything else - the kernel creates a process. A process is the running instance of that program, with its own memory space, open files, and system resources. Every process gets a unique Process ID or PID. This number identifies the process throughout its lifetime and is how you reference it when sending signals or monitoring. PIDs are assigned sequentially but can be reused after a process ends. The Parent Process ID (PPID) indicates which process created this one. When you run a command from bash, the new process's PPID is the bash shell's PID. This creates a process tree with parent-child relationships. Every process has a state indicating what it's currently doing - actively running, waiting for something, stopped, or defunct. We'll cover states in detail shortly. Processes also have a priority or "nice" value that affects how much CPU time they get relative to other processes. On RHEL, systemd is PID 1 - the first process started by the kernel and the ancestor of all other processes. It's responsible for starting and managing system services.
Process States
R - Running: Actively using CPU or ready to run
S - Sleeping: Waiting for an event (input, timer)
D - Disk Sleep: Waiting for I/O, cannot be interrupted
T - Stopped: Suspended by signal (Ctrl+Z) or debugger
Z - Zombie: Finished but parent hasn't read exit status
I - Idle: Kernel thread not doing work
Process states tell you what a process is currently doing. Understanding states helps you diagnose system behavior and identify problems. Running (R) means the process is either actively executing on a CPU or is ready to run and waiting for CPU time. On a busy system, many "runnable" processes might be waiting their turn. Interruptible Sleep (S) is the most common state. The process is waiting for something - user input, a timer, network data, or another event. It can be woken by signals. Most processes spend most of their time sleeping. Uninterruptible Sleep (D) means the process is waiting for I/O (typically disk) and cannot be interrupted, even by signals. Processes stuck in D state waiting for a hung NFS mount or failing disk are problematic because they can't be killed normally. Stopped (T) means the process has been suspended, usually by Ctrl+Z from a terminal or by a debugger. It's not running but hasn't exited - it can be resumed. Zombie (Z) is a terminated process whose parent hasn't yet collected its exit status. The process isn't using resources except a process table entry. A few zombies are normal; many indicate a parent process not properly handling child termination. Idle (I) is used for kernel threads that aren't currently doing work.
Viewing Processes: ps
[student@server ~]$ ps
PID TTY TIME CMD
1234 pts/0 00:00:00 bash
5678 pts/0 00:00:00 ps
[student@server ~]$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 171820 13256 ? Ss Dec07 0:03 /usr/lib/systemd/systemd
root 2 0.0 0.0 0 0 ? S Dec07 0:00 [kthreadd]
student 1234 0.0 0.0 226524 5432 pts/0 Ss 09:00 0:00 -bash
apache 5678 0.0 0.2 274448 20480 ? S 09:01 0:00 /usr/sbin/httpd
[student@server ~]$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Dec07 ? 00:00:03 /usr/lib/systemd/systemd
root 2 0 0 Dec07 ? 00:00:00 [kthreadd]
student 1234 1200 0 09:00 pts/0 00:00:00 -bash
ps aux vs ps -ef: Both show all processes. aux is BSD style (no dash), -ef is UNIX style. Choose based on which columns you need.
The ps command provides a snapshot of current processes. Unlike top, which updates continuously, ps shows the state at the moment you run it. Plain ps with no arguments shows only processes owned by you that are attached to your current terminal - usually just your shell and ps itself. Not very useful by itself. "ps aux" is the most common form - it shows all processes from all users in BSD-style output. The columns show: USER (owner), PID, CPU percentage, memory percentage, virtual memory size (VSZ), resident memory (RSS), terminal (? means no terminal), state (STAT), start time, CPU time used, and the command. "ps -ef" is the UNIX-style equivalent. It shows: UID (user), PID, PPID (parent PID), C (CPU utilization), start time, terminal, CPU time, and command. The PPID column is useful for understanding process relationships. Note BSD style uses no dash before options (aux), while UNIX style uses dashes (-ef). Both work in Linux; it's largely preference. The aux format is more common in practice because it shows CPU and memory percentages directly.
Understanding ps Output
root 1 0.1 0.2 171820 13256 ? Ss Dec07 0:03 /usr/lib/systemd/systemd
apache 5678 2.5 1.0 274448 81920 ? S 09:01 0:45 /usr/sbin/httpd -DFOREGROUND
student 9012 0.0 0.0 226524 5432 pts/0 S+ 10:30 0:00 vim document.txt
root 9999 95.0 0.1 125000 10240 ? R 10:35 5:00 /opt/app/runaway
Column
Description
USER Process owner
PID Process ID
%CPU CPU usage percentage
%MEM Memory usage percentage
VSZ Virtual memory size (KB)
RSS Resident Set Size - physical memory used (KB)
TTY Controlling terminal (? = none/daemon)
STAT Process state + modifiers
START Start time or date
TIME Cumulative CPU time
COMMAND Command with arguments
Let's decode the ps aux output columns in detail. USER shows who owns the process - important for knowing whose processes you're seeing and what permissions they have. PID is the unique process identifier you'll use with kill and other commands. %CPU and %MEM show resource usage. A process consistently using high CPU or memory might need investigation. Note %CPU can exceed 100% on multi-core systems. VSZ (Virtual Size) is total virtual memory allocated, including memory that's been allocated but not yet used. RSS (Resident Set Size) is the actual physical memory being used - this is the more meaningful memory metric. TTY shows the controlling terminal. Processes started from a terminal show pts/0, pts/1, etc. Daemons and background services show ? meaning no terminal. STAT is the state code with modifiers: s means session leader, + means foreground process, < means high priority, N means low priority, l means multi-threaded. In our examples, Ss is a sleeping session leader (systemd), S+ is sleeping foreground process (vim), R is running. START shows when the process began - time if today, date if older. TIME is cumulative CPU time consumed, not wall-clock time - useful for finding processes that have used lots of CPU.
Filtering ps Output
[student@server ~]$ ps aux | grep httpd
apache 5678 0.0 0.2 274448 20480 ? S 09:01 0:00 /usr/sbin/httpd
apache 5679 0.0 0.2 274448 20480 ? S 09:01 0:00 /usr/sbin/httpd
student 9876 0.0 0.0 12345 980 pts/0 S+ 10:40 0:00 grep --color=auto httpd
[student@server ~]$ ps aux | grep [h]ttpd
[student@server ~]$ ps aux | grep httpd | grep -v grep
[student@server ~]$ pgrep httpd
5678
5679
[student@server ~]$ pgrep -a httpd
5678 /usr/sbin/httpd -DFOREGROUND
5679 /usr/sbin/httpd -DFOREGROUND
[student@server ~]$ ps -u apache
[student@server ~]$ pgrep -u apache
With hundreds of processes running, you need ways to filter ps output to find what you're looking for. The classic method is piping ps aux through grep. "ps aux | grep httpd" finds lines containing httpd. However, the grep process itself often shows up in results because its command line contains the search term. Two tricks avoid this: the bracket trick "grep [h]ttpd" makes the grep command line contain [h]ttpd which doesn't match httpd. Or use "grep -v grep" to exclude lines containing grep. The pgrep command is designed specifically for finding processes by name. It returns just the PIDs, which is useful for scripts. pgrep -a shows the full command line along with PIDs. pgrep -l shows process names with PIDs. You can filter by user with -u: "pgrep -u apache" finds all processes owned by the apache user. This is useful for finding all processes belonging to a specific service account. The ps command also supports user filtering: "ps -u apache" shows processes for that user. Combining these filtering techniques lets you quickly find the processes you're interested in among potentially thousands running.
Real-time Monitoring: top
[student@server ~]$ top
top - 10:45:32 up 1 day, 2:30, 2 users, load average: 0.15, 0.10, 0.05
Tasks: 245 total, 1 running, 244 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.3 us, 1.0 sy, 0.0 ni, 96.5 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7963.4 total, 2048.0 free, 3072.0 used, 2843.4 buff/cache
MiB Swap: 4096.0 total, 4096.0 free, 0.0 used. 4512.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5678 apache 20 0 274448 81920 40960 S 2.5 1.0 0:45.23 httpd
1234 student 20 0 226524 5432 3500 S 0.3 0.1 0:01.50 bash
1 root 20 0 171820 13256 10240 S 0.0 0.2 0:03.45 systemd
Interactive Commands:
q - Quit
h - Help
k - Kill a process
r - Renice a process
Sorting:
M - Sort by memory
P - Sort by CPU (default)
T - Sort by time
N - Sort by PID
While ps gives a snapshot, top provides real-time, continuously updating process information. It's essential for monitoring system performance and finding resource-hungry processes. The header shows system overview: uptime, number of users, load averages (1, 5, and 15-minute averages of processes wanting CPU). Load average roughly equal to CPU count means full utilization. The Tasks line shows process counts by state. Running should be low unless you're doing heavy computation. Many zombies indicate a problem. The CPU line breaks down CPU usage: us (user processes), sy (system/kernel), ni (nice - low priority user processes), id (idle), wa (waiting for I/O), hi (hardware interrupts), si (software interrupts), st (stolen - relevant in VMs). Memory shows RAM usage. "buff/cache" is memory used for caching that can be freed if needed. "avail Mem" is how much is actually available for new processes. The process list shows individual processes sorted by CPU usage by default. Interactive commands let you control top: k kills a process (prompts for PID and signal), r renices a process (changes priority), M sorts by memory instead of CPU, and q quits.
Understanding Load Average
[student@server ~]$ uptime
10:45:32 up 1 day, 2:30, 2 users, load average: 0.15, 0.10, 0.05
[student@server ~]$ cat /proc/loadavg
0.15 0.10 0.05 1/245 9876
[student@server ~]$ nproc
4
[student@server ~]$ lscpu | grep "^CPU(s):"
CPU(s): 4
Interpreting Load Average:
Load = 1.00 on single CPU = 100% utilized
Load = 4.00 on 4 CPUs = 100% utilized
Load > CPU count = processes waiting for CPU
Compare 1/5/15 minute values to see trends
Load average is one of the most important system health metrics. It represents the average number of processes that are either running or waiting to run over 1, 5, and 15 minutes. Understanding load requires knowing your CPU count. On a single-core system, load of 1.0 means the CPU is fully utilized with no waiting. Load of 2.0 means one process is running while another waits. On a 4-core system, load of 4.0 means all cores are busy but nothing is waiting. Load of 8.0 means processes are queuing for CPU time. As a rule of thumb, sustained load above your CPU count indicates the system is overloaded. Occasional spikes are normal during peak activity. The three values help identify trends: if the 1-minute average is higher than 15-minute, load is increasing. If 1-minute is lower than 15-minute, the system is recovering from higher load. The uptime command shows load along with how long the system has been running. The same information appears in top's header and in /proc/loadavg. The nproc command shows how many CPU cores you have for comparison. Note that high I/O wait (processes waiting for disk) also contributes to load average, so high load doesn't always mean CPU saturation.
Introduction to Signals
Signals are software interrupts sent to processes to trigger specific behaviors. They're the primary mechanism for controlling processes.
1
SIGHUP
Hangup - reload configuration
2
SIGINT
Interrupt - Ctrl+C
9
SIGKILL
Kill - force terminate (cannot be caught)
15
SIGTERM
Terminate - graceful shutdown (default)
18
SIGCONT
Continue - resume stopped process
19
SIGSTOP
Stop - pause process (cannot be caught)
20
SIGTSTP
Terminal Stop - Ctrl+Z
3
SIGQUIT
Quit - Ctrl+\ with core dump
[student@server ~]$ kill -l
Signals are the Unix way to communicate with processes. When you press Ctrl+C to stop a command, you're sending a signal. The kill command, despite its name, sends signals that don't necessarily kill anything. SIGHUP (1) originally meant "hangup" from when terminals were connected via phone lines. Now it's commonly used to tell daemons to reload their configuration without restarting. SIGINT (2) is the interrupt signal sent by Ctrl+C. Programs can catch it to clean up before exiting. SIGKILL (9) is the "nuclear option" - it immediately terminates the process. The process cannot catch, block, or ignore it. The kernel handles it directly. Use only when SIGTERM fails. SIGTERM (15) is the default signal sent by kill. It asks the process to terminate gracefully, allowing cleanup of temporary files, closing connections, etc. Always try this first. SIGSTOP (19) pauses a process - it stops running but doesn't terminate. SIGCONT (18) resumes it. SIGSTOP cannot be caught or ignored. SIGTSTP (20) is the terminal stop signal sent by Ctrl+Z. Unlike SIGSTOP, processes can catch it. "kill -l" lists all signals. There are about 30 standard signals; some have specialized uses.
The kill Command
[root@server ~]# kill 5678
[root@server ~]# kill -15 5678
[root@server ~]# kill -SIGTERM 5678
[root@server ~]# kill -TERM 5678
[root@server ~]# kill -9 5678
[root@server ~]# kill -SIGKILL 5678
[root@server ~]# kill -KILL 5678
[root@server ~]# kill -1 5678
[root@server ~]# kill -HUP 5678
[root@server ~]# kill 5678 5679 5680
[root@server ~]# ps aux | grep 5678
⚠ Best Practice: Always try kill (SIGTERM) first. Only use kill -9 (SIGKILL) if SIGTERM doesn't work after a few seconds.
The kill command sends signals to processes. Despite its name, it doesn't always kill - it sends whatever signal you specify. With no signal specified, kill sends SIGTERM (15), the graceful termination request. The process receives the signal and should clean up and exit. You can specify signals by number (-9, -15), by full name (-SIGKILL, -SIGTERM), or by short name (-KILL, -TERM). All are equivalent. SIGKILL (-9) should be your last resort. It doesn't give the process a chance to clean up - temporary files may be left behind, database transactions may be incomplete, connections may not be closed properly. But it will definitely stop the process because it can't be caught or ignored. SIGHUP (-1) traditionally means "hangup" but many daemons use it to reload configuration. "kill -HUP $(pgrep httpd)" tells Apache to reread its config files without restarting. You can kill multiple processes by listing multiple PIDs. After killing, verify the process is gone with ps or pgrep. If using SIGTERM and the process doesn't exit within a few seconds, it might be stuck. Then try SIGKILL. Regular users can only signal their own processes. Root can signal any process.
killall and pkill
[root@server ~]# killall httpd
[root@server ~]# killall -9 httpd
[root@server ~]# killall -i httpd
[root@server ~]# killall -u student
[root@server ~]# pkill httpd
[root@server ~]# pkill -9 httpd
[root@server ~]# pkill -u apache
[root@server ~]# pkill -u apache httpd
[root@server ~]# pkill -t pts/0
[root@server ~]# killall http
http: no process found
[root@server ~]# pkill http
pgrep + kill vs pkill: pgrep -a pattern shows what would match. Use this to verify before running pkill.
While kill requires PIDs, killall and pkill work with process names - much more convenient when you know the program name but not the PID. killall sends a signal to all processes with an exact name match. "killall httpd" sends SIGTERM to every process named exactly "httpd". The -i flag asks for confirmation for each process - useful for safety. The -u flag targets processes owned by a specific user. pkill is more flexible because it uses pattern matching. "pkill http" matches httpd, http-server, and anything else containing "http" in the name. This is convenient but requires care to avoid killing unintended processes. pkill supports the same -u flag for user filtering. You can combine filters: "pkill -u apache httpd" kills httpd processes owned by apache user. The -t flag targets processes on a specific terminal. Both commands accept signal specifications like kill: -9 for SIGKILL, -HUP for SIGHUP, etc. Before using pkill on production systems, use pgrep with the same pattern to see what would match. "pgrep -a http" shows matching processes without killing them. This prevents accidentally killing the wrong processes.
Termination Order
Step 1: SIGTERM (15)
Polite request to terminate
↓ Wait a few seconds
Step 2: Check if running
ps or pgrep to verify
↓ Still running?
Step 3: SIGKILL (9)
Force kill - last resort
[root@server ~]# kill 5678
[root@server ~]# sleep 3
[root@server ~]# pgrep -a 5678 || echo "Process ended"
[root@server ~]# kill -9 5678
When terminating processes, following the proper order prevents data loss and system issues. Think of it as escalating force only when necessary. Step 1: Always start with SIGTERM (signal 15). This is the default signal sent by kill without arguments. It tells the process "please shut down gracefully." Well-written programs catch this signal, save their state, close files, release resources, and exit cleanly. Step 2: Wait a few seconds and check if the process is still running. Use ps or pgrep. Some processes take time to shut down - they might be finishing transactions, closing network connections, or writing final data. Step 3: Only if the process is still running after a reasonable wait should you use SIGKILL (signal 9). This immediately terminates the process with no chance for cleanup. The process doesn't even receive the signal - the kernel just stops it. Why does this matter? A database receiving SIGTERM will finish current transactions and flush data to disk. Receiving SIGKILL, it just stops - transactions may be lost, data might be corrupted, requiring recovery on restart. A web server receiving SIGTERM will finish serving current requests. With SIGKILL, users get broken connections. The example code shows this sequence: try SIGTERM, wait, check, then SIGKILL only if needed.
Keyboard Signals
Keys
Signal
Effect
Ctrl +C
SIGINT (2)
Interrupt - stop the process (can be caught)
Ctrl +Z
SIGTSTP (20)
Suspend - pause and send to background
Ctrl +\
SIGQUIT (3)
Quit - terminate with core dump
[student@server ~]$ find / -name "*.conf"
/etc/httpd/conf/httpd.conf
/etc/ssh/sshd_config
^C
[student@server ~]$ vim document.txt
[1]+ Stopped vim document.txt
[student@server ~]$ bg
[student@server ~]$ fg
[student@server ~]$ ./stubborn-program
^\Quit (core dumped)
These keyboard shortcuts send signals to the foreground process in your terminal. They're the quickest way to control processes you started. Ctrl+C sends SIGINT (interrupt). Most programs catch this and exit gracefully. It's the standard way to stop a running command. Some programs catch it and ask for confirmation or ignore it if they're doing something critical. Ctrl+Z sends SIGTSTP (terminal stop), which suspends the process. It doesn't terminate - the process pauses and becomes a stopped background job. The shell reports the job number in brackets. This is incredibly useful when you need to temporarily stop what you're doing to run another command, then resume. Use "fg" to bring the suspended process back to the foreground, or "bg" to let it continue in the background. We'll cover job control in more detail shortly. Ctrl+\ sends SIGQUIT, which is like a stronger Ctrl+C. It not only terminates the process but also generates a core dump (memory snapshot) for debugging. Use this when Ctrl+C doesn't work, though be aware it creates a core file. These only work on the foreground process in your terminal. Background processes and processes in other terminals require kill or similar commands.
Job Control
[student@server ~]$ sleep 300 &
[1] 5678
[student@server ~]$ jobs
[1]+ Running sleep 300 &
[student@server ~]$ vim document.txt
[1]+ Stopped vim document.txt
[student@server ~]$ fg
[student@server ~]$ fg %1
[student@server ~]$ bg
[student@server ~]$ bg %1
[student@server ~]$ kill %1
[student@server ~]$ jobs
[1] Running sleep 300 &
[2]- Stopped vim file.txt
[3]+ Running ./script.sh &
Job control lets you manage multiple processes from a single terminal, running some in the background while interacting with others in the foreground. The ampersand (&) at the end of a command runs it in the background immediately. The shell reports the job number in brackets and the PID. You get your prompt back immediately while the command runs. The jobs command lists all jobs for your current shell session. Plus (+) marks the current/default job, minus (-) marks the previous job. These are the jobs that fg and bg affect when you don't specify a number. Ctrl+Z suspends the foreground process, making it a stopped job. This is useful when you need to do something else without terminating what you were doing. "fg" brings a stopped or background job to the foreground. Without arguments, it affects the current job (+). Use %1, %2, etc. to specify a particular job number. "bg" resumes a stopped job in the background. The job continues running but you keep your prompt. Not all programs work well in the background - anything expecting terminal input will stop again. You can kill jobs by job number: "kill %1" is more convenient than finding the PID. When you close a terminal, background jobs typically receive SIGHUP and terminate. Use nohup or disown to prevent this if needed.
Background Processes
[student@server ~]$ ./long-script.sh > output.log 2>&1 &
[1] 5678
[student@server ~]$ nohup ./long-script.sh &
[1] 5678
nohup: ignoring input and appending output to 'nohup.out'
[student@server ~]$ nohup ./script.sh > script.log 2>&1 &
[student@server ~]$ ./process &
[student@server ~]$ disown %1
[student@server ~]$ nohup ./daemon-script.sh &
[student@server ~]$ exit
[student@server ~]$ screen -S mysession
[student@server ~]$ ./long-process
[student@server ~]$ screen -r mysession
Running processes in the background is essential for long-running tasks, but there are important considerations for keeping them running reliably. Simply adding & runs a command in the background, but if the terminal closes, the process receives SIGHUP and typically terminates. Also, output still goes to the terminal unless redirected. Redirecting output when backgrounding prevents the background process from trying to write to a terminal that might be closed. "2>&1" redirects stderr to wherever stdout goes, capturing all output in one file. nohup (no hangup) makes a process ignore SIGHUP, so it continues when you log out. By default, output goes to nohup.out. Combine with output redirection for better control over where output goes. The disown command removes a job from the shell's job table. After disowning, the shell won't send SIGHUP when it exits. This is useful for backgrounding something after it's started. For truly long-running tasks or interactive programs that need to survive disconnection, use screen or tmux. These create persistent terminal sessions you can detach from and reattach to later, even from different connections. This is especially valuable for remote administration - start something in screen, disconnect, come back later.
Process Priority
The nice value influences process scheduling priority. Lower values = higher priority. Range: -20 (highest) to +19 (lowest).
-20 to -1
High Priority(requires root)
0
Default(normal processes)
+1 to +19
Low Priority(background tasks)
[student@server ~]$ nice -n 10 ./background-task.sh
[root@server ~]# nice -n -5 ./important-task.sh
[student@server ~]$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1000 1234 1200 0 80 0 - 5678 - pts/0 00:00:00 bash
0 R 1000 5678 1234 0 90 10 - 2345 - pts/0 00:00:05 background-task
Process priority determines how much CPU time a process gets relative to others. Linux uses a "nice" value system where being "nicer" means taking less priority. Nice values range from -20 (highest priority, least nice to other processes) to +19 (lowest priority, nicest to others). The default is 0. A process with nice value -10 gets more CPU time than one with +10 when both are competing for CPU. The nice command starts a process with a specified nice value. "nice -n 10 command" starts with nice value 10 (lower priority than default). Regular users can only increase nice values (lower their priority). Only root can set negative nice values to increase priority. In ps output, the NI column shows nice value and PRI shows the actual kernel priority (higher PRI = lower priority, confusingly). Use nice for batch jobs, backups, or anything that shouldn't interfere with interactive performance. A backup script running at nice +15 will automatically yield to user processes. High-priority (negative nice) should be used sparingly and only for truly critical processes, as it can starve other processes of CPU time.
Changing Priority: renice
[student@server ~]$ renice 10 -p 5678
5678 (process ID) old priority 0, new priority 10
[root@server ~]# renice 5 -u student
1000 (user ID) old priority 0, new priority 5
[root@server ~]# renice -5 -p 5678
5678 (process ID) old priority 10, new priority -5
[student@server ~]$ ps -eo pid,ni,comm | head
PID NI COMMAND
1 0 systemd
2 0 kthreadd
5678 10 background-task
Remember: Users can only increase nice values (lower priority). Only root can decrease nice values (raise priority).
renice changes the priority of already-running processes. This is useful when you realize a process is consuming too many resources or when you need to boost something important. The basic syntax is "renice value -p PID". The value is the new nice value, and -p specifies you're targeting a process ID. Multiple PIDs can be specified. With -u, you can change the nice value for all processes owned by a user. This is useful for lowering the priority of a user who's running too many intensive tasks. Users can only increase the nice value of their own processes (making them nicer/lower priority). They cannot decrease nice values because that would let any user grab more CPU priority. Only root can decrease nice values, increasing priority. This restriction prevents users from competing to have the highest priority. Inside top, pressing 'r' lets you renice a process interactively. It prompts for PID and new nice value - convenient when you're already monitoring with top. The ps command with -eo lets you select specific columns. "pid,ni,comm" shows PID, nice value, and command name, making it easy to see current priorities without the clutter of full ps output.
Process Info in /proc
[student@server ~]$ ls /proc
1 1234 2 245 5678 acpi bus cmdline cpuinfo ...
[student@server ~]$ ls /proc/5678
cmdline cwd environ exe fd maps status ...
[student@server ~]$ cat /proc/5678/cmdline
/usr/sbin/httpd-DFOREGROUND
[student@server ~]$ cat /proc/5678/status | head -10
Name: httpd
State: S (sleeping)
Pid: 5678
PPid: 1
Uid: 48 48 48 48
Gid: 48 48 48 48
[student@server ~]$ cat /proc/5678/maps | head
[student@server ~]$ ls -l /proc/5678/fd
The /proc filesystem is a virtual filesystem that provides information about processes and the kernel. Each running process has a numbered directory matching its PID. Inside each process directory, you find various files containing process information. cmdline shows the command line used to start the process - arguments are null-separated rather than space-separated. status provides detailed information about the process state, including name, state, PID, parent PID, user and group IDs, memory usage, and more. This is the raw data that commands like ps read. cwd is a symbolic link to the process's current working directory. exe links to the executable file. environ contains the process's environment variables. fd is a directory containing symbolic links for each open file descriptor. This shows what files, sockets, and pipes the process has open. maps shows the process's memory map - what's loaded where in its virtual memory space. These files are useful for deep debugging when standard tools don't provide enough information. They're also how tools like ps, top, and pgrep work - they read from /proc to gather process information.