Introduction
A running Linux system is more than its files. The kernel manages hardware and processes, each command runs as a process with an identifier, and the shell tracks foreground and background jobs. Administrators first observe this state, then act on the smallest relevant process.
In this lab, you will identify the operating system and kernel, interpret uptime and load averages, inspect process relationships, find processes by name, send termination signals, practice interactive job control, interpret exit status, run a detached command with nohup, and read recent kernel messages.
Identify the System and Interpret Load
In this step, you will identify the kernel and distribution, check how long the system has been running, and learn what load averages represent.
Create and enter a workspace:
mkdir -p /home/labex/project/process-lab
cd /home/labex/project/process-lab
The uname command reports kernel information. The options -s, -r, and -m select the kernel name, kernel release, and machine architecture:
uname -srm
uname -a displays all available fields in one line:
uname -a
The kernel is not the same thing as the Linux distribution. Read the distribution metadata:
cat /etc/os-release
Look for fields such as NAME, VERSION, and ID. Next, check uptime and load:
uptime
The output includes the current time, how long the system has been running, the number of logged-in users, and three load averages. Those averages describe runnable or uninterruptible work over approximately 1, 5, and 15 minutes. They are not percentages; their meaning depends partly on the number of CPU cores.
View the kernel's compact load record:
cat /proc/loadavg
The first three values match the load-average idea. Later fields show runnable tasks and the most recently assigned process ID.
Save a small system summary for later reference:
uname -srm > system-summary.txt
uptime >> system-summary.txt
cat system-summary.txt
The file should contain one kernel line and one uptime line.
Inspect Processes and Resource Activity
In this step, you will inspect process identifiers, parent relationships, states, and a snapshot of system resource activity.
A process is a running program. Every process has a process ID, or PID. Most processes also have a parent process ID, or PPID, identifying the process that started them.
The ps command displays a process snapshot. Select useful fields and sort by PID:
cd /home/labex/project/process-lab
ps -eo pid,ppid,user,stat,comm --sort=pid | head -n 15
The -e option selects all processes and -o defines the columns:
PIDis the process identifier.PPIDis the parent identifier.USERis the process owner.STATis the process state plus optional flags.COMMANDis the executable name.
Common state letters include R for running, S for interruptible sleep, D for uninterruptible sleep, T for stopped, and Z for zombie. A sleeping process is often simply waiting for work.
The BSD-style ps aux form provides CPU and memory columns plus complete command lines:
ps aux | head -n 10
top updates continuously when used interactively. Batch mode makes one stable snapshot: -b selects batch output and -n 1 requests one update.
top -b -n 1 | head -n 12
The header summarizes uptime, load, task states, CPU use, and memory. The process table below it helps locate active resource consumers.
Now open the interactive display:
top
Watch the values update, locate the %CPU and %MEM columns, and then press q to return to the shell. Interactive top is useful when you need to observe changes over time; batch mode is better when output must be saved or processed by another command.
Save a focused process snapshot as an observable result:
ps -eo pid,ppid,user,stat,comm --sort=pid > process-snapshot.txt
head -n 5 process-snapshot.txt
Start and Locate a Practice Process
In this step, you will start a harmless background process, capture its PID, and locate it with both ps and pgrep.
The trailing & asks the shell to run a command in the background and return the prompt immediately. Start a five-minute sleep process with the visible name labex-worker:
cd /home/labex/project/process-lab
bash -c 'exec -a labex-worker sleep 300' &
The special shell value $! contains the PID of the most recently started background process. Save it before starting another background command:
worker_pid=$!
echo "$worker_pid" > worker.pid
Inspect exactly that process. The -p option selects a PID and -o chooses fields:
ps -o pid,ppid,user,stat,etime,args -p "$worker_pid"
ETIME shows elapsed runtime, while ARGS includes the visible process name. Use pgrep -f to search the complete command line; -a also prints it:
pgrep -af labex-worker
The PID from pgrep should match worker.pid. Searching by a precise pattern is safer than acting on every process with a broad name.
Stop Processes with Signals
In this step, you will request a graceful termination with SIGTERM and use SIGKILL only for a process designed to ignore that request.
The kill command sends a signal to a PID. Without an explicit signal, it sends SIGTERM, signal 15. SIGTERM requests an orderly shutdown and gives the process a chance to clean up.
Read the worker PID and send SIGTERM:
cd /home/labex/project/process-lab
worker_pid=$(cat worker.pid)
kill "$worker_pid"
sleep 1
The following expected ps failure proves the process ended:
ps -p "$worker_pid" || echo "labex-worker stopped after SIGTERM"
Now start a controlled process that intentionally ignores SIGTERM:
bash -c 'trap "" TERM; exec -a labex-stubborn sleep 300' &
stubborn_pid=$!
echo "$stubborn_pid" > stubborn.pid
Give the new shell a moment to install its signal handler:
sleep 1
Send SIGTERM, wait briefly, and inspect the process:
kill -TERM "$stubborn_pid"
sleep 1
ps -o pid,stat,args -p "$stubborn_pid"
It should still be present because this practice process ignores SIGTERM. SIGKILL, signal 9, cannot be caught or ignored. Use it only after a graceful signal is ineffective:
kill -KILL "$stubborn_pid"
Reap the terminated background job. The nonzero status is expected, so || true lets the practice sequence continue:
wait "$stubborn_pid" 2>/dev/null || true
ps -p "$stubborn_pid" || echo "labex-stubborn required SIGKILL"
SIGKILL gives a process no opportunity to save state or release application resources cleanly, so it is a last resort.
kill targets a known PID. When you need to select a process by its name or full command line, pkill combines matching and signaling. Start one more controlled process with a distinctive command line:
bash -c 'exec -a labex-helper sleep 300' &
helper_pid=$!
echo "$helper_pid" > helper.pid
Confirm the exact full-command match before acting:
pgrep -af '^labex-helper 300$'
Send SIGTERM to that exact match with pkill -f. The anchors ^ and $ keep this training pattern from matching unrelated command lines:
pkill -TERM -f '^labex-helper 300$'
wait "$helper_pid" 2>/dev/null || true
ps -p "$helper_pid" || echo "labex-helper stopped by pkill"
Use precise pkill patterns and inspect matches first with pgrep; broad patterns can stop more processes than intended.
Control Foreground and Background Jobs
In this step, you will suspend a foreground command, resume it in the background, return it to the foreground, and interrupt it.
Job control belongs to the current interactive shell. Start a foreground sleep process with a recognizable name:
cd /home/labex/project/process-lab
bash -c 'exec -a labex-job sleep 300'
The terminal is now occupied by the foreground process. Press Ctrl+Z. The shell sends a stop signal and returns the prompt.
List jobs known to this shell. The -l option includes the process ID:
jobs -l
You should see a Stopped job. Resume job number 1 in the background:
bg %1
jobs -l
The state should now be Running, and the prompt remains available. Bring the job back to the foreground:
fg %1
Press Ctrl+C to send an interrupt signal to the foreground job. The prompt should return. Confirm that no practice job remains:
pgrep -af labex-job || echo "No labex-job process remains"
Create a completion marker after you have finished the interactive sequence:
touch job-control.done
Use job control for commands attached to the current terminal. Later you will use nohup for work that should not depend on the terminal session.
Read Exit Status and Run Detached Work
In this step, you will interpret command exit status and run a short background task whose output survives independently of the terminal display.
Every command returns an integer status. Zero means success; a nonzero value means some kind of failure. The shell variable $? contains the status of the command that just finished.
Run a successful command, then immediately print its status:
cd /home/labex/project/process-lab
true
echo "true status: $?"
The result is 0. Now run a command that cannot find its path:
ls missing-path
Capture its status before another command replaces $?:
missing_status=$?
echo "missing-path status: $missing_status"
The value is nonzero. Save both expected interpretations:
printf 'success=0\nfailure=%s\n' "$missing_status" > exit-status.txt
The nohup command makes a program ignore the terminal hangup signal. The final & starts it in the background. The redirection < /dev/null disconnects terminal input, while > nohup.log 2>&1 sends both output streams to a log:
nohup bash -c 'for item in one two three; do echo "background: $item"; sleep 1; done' < /dev/null > nohup.log 2>&1 &
Save the background PID and allow the short task to finish:
echo $! > nohup.pid
sleep 4
cat nohup.log
You should see three lines, from background: one through background: three. For long-running work, the saved PID and log provide ways to inspect progress.
Inspect Recent Kernel Messages
In this step, you will inspect the kernel message buffer and save the running kernel release as a stable reference.
The kernel records messages about startup, hardware, drivers, and runtime events in a ring buffer. dmesg reads that buffer. Administrative privileges are commonly required:
cd /home/labex/project/process-lab
sudo dmesg | tail -n 10
The exact messages vary by machine and time. Focus on the timestamp-like field and the component or subsystem that produced each message.
The --level option filters by severity. Display recent warnings and errors:
sudo dmesg --level=err,warn | tail -n 10
No output does not mean the command failed; it can mean that the current buffer has no messages at those levels. Search recent messages for common storage and network terms:
sudo dmesg | grep -Ei 'disk|filesystem|network|eth' | tail -n 10
Again, results depend on the current system. Save the kernel release reported by uname -r:
uname -r > kernel-version.txt
cat kernel-version.txt
Kernel messages are evidence, not automatic diagnoses. Combine them with process state, service logs, and observed symptoms before deciding on an action.
Summary
You identified a Linux system, interpreted uptime and load averages, and inspected process IDs, parents, owners, states, and resource activity with both snapshot and interactive tools. You started and found named processes, targeted them precisely with kill and pkill, used SIGTERM before SIGKILL, and practiced foreground and background job control.
You also interpreted exit status, ran detached work with nohup and explicit logging, and inspected kernel messages with dmesg. These observation-first habits are the foundation of safe process troubleshooting and prepare you for service, logging, and network diagnostics later in the course.



