\chapter{Linux Commands} \ChapterLabel{LinuxCommands} \index{Linux} \index{Linux!command line} \index{Linux!working directory} \index{bash} \index{symbolic link} \index{file timestamps} \section{Purpose} This chapter records a set of Linux shell commands run in the authors' working user directories, and the solutions to the accompanying problem set. The setup figures reproduce Payton's terminal session. Section~\ref{Section:LinuxEvidence} adds Victor's actual problem-set execution screenshots as \gls{evidence}. The command answers in Section~\ref{Section:LinuxSolutions} describe solutions; where Victor used a different command, the difference is identified rather than presented as an execution of the exact answer shown. \section{Environment} \index{Linux!environment} The setup figures were recorded by Payton as user \texttt{payton} on Ubuntu~24.04 under \gls{wsl}, in a \texttt{bash} shell. Victor independently performed the setup and problem set on September 27, 2026, as user \texttt{victor} on host \texttt{Victori7}, running Ubuntu~24.04.3 LTS under WSL~2. His working directory was \texttt{/home/victor/lx-test}. The session was recorded with \texttt{script}; its original transcript is retained with the evidence files. Normal commands ran without elevated privileges; \texttt{sudo} was used for the append-only attribute in Q20. \section{Working Directory Setup} \index{Linux!working directory setup} Figure~\ref{Figure:LxTestSetup} shows the executed setup commands in the order given by the assignment. Figure~{\ref{Figure:LxTestDirectories}} shows the resulting directory structure, and Figure~{\ref{Figure:LxTestFiles}} shows the resulting file contents. \subsection{What the Commands Do} \index{Linux!command explanations} \begin{sloppypar} \begin{itemize}[leftmargin=*] \item \texttt{mkdir -p \textasciitilde/lx-test \&\& cd \textasciitilde/lx-test} creates the directory, along with any missing parent directories, and does not fail if it already exists. The \texttt{\&\&} operator runs \texttt{cd} only if \texttt{mkdir} succeeds. \item \texttt{printf "\ldots" > \textit{file}} writes the string to a file, turning each \texttt{\textbackslash n} into a newline. The \texttt{>} redirection creates the file or overwrites it if it already exists. \texttt{printf} is used instead of \texttt{echo} for predictable formatting of these strings and newlines, avoiding shell-dependent behavior of \texttt{echo}. \item \texttt{dd} with \texttt{if=/dev/zero}, \texttt{of=blob.bin}, \texttt{bs=1K}, and \texttt{count=48} copies $48$ blocks of $1\,\mathrm{KiB}$ from \texttt{/dev/zero}, producing a file of $48 \times 1024 = 49152$ zero bytes. \item \texttt{mkdir -p src/lib tmp archive} creates three directories in one command; \texttt{-p} creates \texttt{src} as the parent of \texttt{lib}. \item \texttt{ln -s src/file1.txt link-to-file1} creates a symbolic link. The stored target is the relative path \texttt{src/file1.txt}, which is resolved relative to the directory that contains the link. \item \texttt{touch -t 202401020304 old.txt} creates \texttt{old.txt} with a modification time of 2024-01-02 03:04 in local time. \item \texttt{ls -lA} lists each named directory in long format, including hidden entries but omitting \texttt{.} and \texttt{..}. \texttt{head} prints the first ten lines of each file under a file name header; every file here is shorter than ten lines, so each is shown in full. \end{itemize} \end{sloppypar} \subsection{Interpretation of Results} \index{Linux!result interpretation} Figure~\ref{Figure:LxTestDirectories} confirms each step of the setup: \begin{itemize}[leftmargin=*] \item \textbf{File sizes:} \texttt{blob.bin} is $49152$ bytes, as computed above. Each text file's size equals its characters plus one byte per newline. \item \textbf{Symbolic link:} \texttt{link-to-file1} has type \texttt{l} and points to \texttt{src/file1.txt}. \item \textbf{Timestamp:} \texttt{old.txt} is empty and shows the modified timestamp (\texttt{Jan~2~2024}). \item \textbf{Directories:} \texttt{archive}, \texttt{tmp}, and \texttt{src/lib} show no entries in the \texttt{ls -lA} listing, confirming they are empty (\texttt{total 0} alone would not prove this). \item \textbf{Permissions:} New files are \texttt{rw-r--r--} ($644$) and new directories are \texttt{rwxr-xr-x} ($755$). \end{itemize} \begin{figure}[htbp] \begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true] payton@paytonpc:~$ mkdir -p ~/lx-test && cd ~/lx-test payton@paytonpc:~/lx-test$ printf "alpha\nbeta\nGamma\ngamma\nbeta\n" > words.txt payton@paytonpc:~/lx-test$ printf "id,name,dept\n1,Ada,EE\n2,Linus,CS\n3,Grace,EE\n4,Dennis,CS\n" > people.csv payton@paytonpc:~/lx-test$ printf "INFO boot ok\nWARN disk low\nERROR fan fail\nINFO shutdown\n" > sys.log payton@paytonpc:~/lx-test$ dd if=/dev/zero of=blob.bin bs=1K count=48 status=none payton@paytonpc:~/lx-test$ mkdir -p src/lib tmp archive payton@paytonpc:~/lx-test$ printf "one two three four\n" > src/file1.txt payton@paytonpc:~/lx-test$ printf "two three four five\n" > src/file2.txt payton@paytonpc:~/lx-test$ ln -s src/file1.txt link-to-file1 payton@paytonpc:~/lx-test$ touch -t 202401020304 old.txt \end{lstlisting} \caption{Terminal input for setting up the \texttt{lx-test} working directory.} \label{Figure:LxTestSetup} \end{figure} \begin{figure}[htbp] \begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true] payton@paytonpc:~/lx-test$ ls -lA . src src/lib archive tmp .: total 72 drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 archive -rw-r--r-- 1 payton payton 49152 Sep 26 15:39 blob.bin lrwxrwxrwx 1 payton payton 13 Sep 26 15:39 link-to-file1 -> src/file1.txt -rw-r--r-- 1 payton payton 0 Jan 2 2024 old.txt -rw-r--r-- 1 payton payton 56 Sep 26 15:39 people.csv drwxr-xr-x 3 payton payton 4096 Sep 26 15:39 src -rw-r--r-- 1 payton payton 56 Sep 26 15:39 sys.log drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 tmp -rw-r--r-- 1 payton payton 28 Sep 26 15:39 words.txt archive: total 0 src: total 12 -rw-r--r-- 1 payton payton 19 Sep 26 15:39 file1.txt -rw-r--r-- 1 payton payton 20 Sep 26 15:39 file2.txt drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 lib src/lib: total 0 tmp: total 0 \end{lstlisting} \caption{Terminal output showing the resulting directories after \texttt{lx-test} setup.} \label{Figure:LxTestDirectories} \end{figure} \begin{figure}[htbp] \begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true] payton@paytonpc:~/lx-test$ head words.txt people.csv sys.log src/file1.txt src/file2.txt ==> words.txt <== alpha beta Gamma gamma beta ==> people.csv <== id,name,dept 1,Ada,EE 2,Linus,CS 3,Grace,EE 4,Dennis,CS ==> sys.log <== INFO boot ok WARN disk low ERROR fan fail INFO shutdown ==> src/file1.txt <== one two three four ==> src/file2.txt <== two three four five \end{lstlisting} \caption{Terminal output showing the resulting file contents after \texttt{lx-test} setup.} \label{Figure:LxTestFiles} \end{figure} \clearpage \section{Problem Set Solutions} \label{Section:LinuxSolutions} \index{Linux!problem set} \subsection{Navigation and File Operations} \begin{enumerate}[label=\arabic*., leftmargin=*] \item Show your present working directory path only. \begin{lstlisting}[style=cmd] $ pwd \end{lstlisting} \nopagebreak[4] \texttt{pwd} prints only the current directory; Victor's result was \texttt{/home/victor/lx-test}. \item List all entries in the current directory, one per line, including dotfiles. \begin{lstlisting}[style=cmd] $ ls -1a \end{lstlisting} \nopagebreak[4] \texttt{-1} places each entry on a separate line; \texttt{-a} includes dotfiles and the \texttt{.} and \texttt{..} entries. \item Copy \texttt{src/file1.txt} to \texttt{tmp/} only if \texttt{tmp} exists; do it verbosely. \begin{lstlisting}[style=cmd] $ [ -d tmp ] && cp -v src/file1.txt tmp/ \end{lstlisting} \nopagebreak[4] The directory test prevents copying when \texttt{tmp} is absent; \texttt{-v} reports the source and destination. Victor's output confirms the copy. \item Move \texttt{old.txt} into \texttt{archive/} and keep its original timestamp. \begin{lstlisting}[style=cmd] $ mv old.txt archive/ \end{lstlisting} \nopagebreak[4] Moving within this working tree preserves the file's modification time. Victor verified that the timestamp remained January 2, 2024 at 03:04 local time. \item Create a new empty file \texttt{notes.md} only if it doesn't already exist. \begin{lstlisting}[style=cmd] $ [ -e notes.md ] || touch notes.md \end{lstlisting} \nopagebreak[4] The existence test avoids touching an existing file. Victor used the equivalent conditional \texttt{if} form and verified that the newly created file was zero bytes. \item Show disk usage (human-readable) for the \texttt{src} directory only (not total FS). \begin{lstlisting}[style=cmd] $ du -sh src \end{lstlisting} \nopagebreak[4] \texttt{-s} reports one directory total and \texttt{-h} uses readable units. Victor observed \texttt{16K}; allocated disk usage includes directory storage and is not simply text length. \end{enumerate} \subsection{Viewing and Searching} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Print line numbers while displaying \texttt{sys.log}. \begin{lstlisting}[style=cmd] $ cat -n sys.log \end{lstlisting} \nopagebreak[4] \texttt{cat -n} numbers displayed lines. Victor used \texttt{nl -ba}, which also numbered all four lines in this file. \item Show only the lines in \texttt{sys.log} that contain \texttt{ERROR} (case-sensitive). \begin{lstlisting}[style=cmd] $ grep 'ERROR' sys.log \end{lstlisting} \nopagebreak[4] Without \texttt{-i}, matching is case-sensitive. The result was \texttt{ERROR fan fail}. \item Count how many distinct words appear in \texttt{words.txt} (case-insensitive). \begin{lstlisting}[style=cmd] $ tr '[:upper:]' '[:lower:]' < words.txt | sort -u | wc -l \end{lstlisting} \nopagebreak[4] Each input line contains one word. Lowercasing before sorting and deduplication treats \texttt{Gamma} and \texttt{gamma} as one value; the resulting count was three. \item From \texttt{words.txt}, show lines that start with \texttt{g} or \texttt{G}. \begin{lstlisting}[style=cmd] $ grep '^[gG]' words.txt \end{lstlisting} \nopagebreak[4] The anchor \texttt{\^{}} restricts the match to the start of the line, and \texttt{[gG]} accepts either case. The two matches were \texttt{Gamma} and \texttt{gamma}. \item Display the first 2 lines of \texttt{people.csv} without using an editor. \begin{lstlisting}[style=cmd] $ head -n 2 people.csv \end{lstlisting} \nopagebreak[4] The first two lines are the header and the first data row: \texttt{id,name,dept} and \texttt{1,Ada,EE}. \item Show the last 3 lines of \texttt{sys.log} and keep following if the file grows. \begin{lstlisting}[style=cmd] $ tail -n 3 -f sys.log \end{lstlisting} \nopagebreak[4] \texttt{-n 3} selects the last three lines; \texttt{-f} keeps following. Victor captured the initial three lines, then stopped following with Ctrl+C. No later appended-line test is claimed. \end{enumerate} \subsection{Text Processing} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item From \texttt{people.csv}, print only the name column (2nd), excluding the header. \begin{lstlisting}[style=cmd] $ tail -n +2 people.csv | cut -d, -f2 \end{lstlisting} \nopagebreak[4] \texttt{tail} skips the header and \texttt{cut} selects the comma-separated second field. Victor's equivalent \texttt{awk} command returned Ada, Linus, Grace, and Dennis. \item Sort \texttt{words.txt} case-insensitively and remove duplicates. \begin{lstlisting}[style=cmd] $ sort -fu words.txt \end{lstlisting} \nopagebreak[4] \texttt{-f} ignores case during comparison and \texttt{-u} removes duplicates. Victor's output was alpha, beta, and Gamma; the retained spelling need not be lowercased. \item Replace every \texttt{three} with \texttt{3} in all files under \texttt{src/} in-place, creating \texttt{.bak} backups. \begin{lstlisting}[style=cmd] $ find src/ -type f ! -name '*.bak' -exec sed -i.bak 's/three/3/g' {} + \end{lstlisting} \nopagebreak[4] \texttt{find} visits regular files recursively, excluding existing backups; \texttt{sed}'s \texttt{g} replaces every occurrence on each line. The original files are saved with the \texttt{.bak} suffix. Victor verified both edited content and original backups. Run once to avoid replacing the original backups on a later run. \item Print the number of lines, words, and bytes for every \texttt{*.txt} file in \texttt{src/}. \begin{lstlisting}[style=cmd] $ wc src/*.txt \end{lstlisting} \nopagebreak[4] By default, \texttt{wc} reports lines, words, and bytes. After Q15, Victor observed \texttt{1 4 15} and \texttt{1 4 16}, totaling \texttt{2 8 31}. Backup filenames do not match \texttt{*.txt}. \end{enumerate} \subsection{Permissions and Ownership} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Make \texttt{tmp/} readable, writable, and searchable only by the owner. \begin{lstlisting}[style=cmd] $ chmod 700 tmp/ \end{lstlisting} \nopagebreak[4] Mode \texttt{700} gives the owner read, write, and directory-search permissions, with none for group or others. Victor verified \texttt{drwx------}. \item Give group execute permission to \texttt{src/lib} recursively without touching others/owner bits. \begin{lstlisting}[style=cmd] $ chmod -R g+x src/lib \end{lstlisting} \nopagebreak[4] \texttt{g+x} adds only group execute; \texttt{-R} applies recursively. Victor's before/after value remained \texttt{755} because group execute was already enabled. \item Show the numeric (octal) permissions of \texttt{src/file2.txt}. \begin{lstlisting}[style=cmd] $ stat -c '%a' src/file2.txt \end{lstlisting} \nopagebreak[4] \texttt{\%a} requests octal permissions. Victor observed \texttt{644}: owner read/write, group and others read-only. \item Make \texttt{notes.md} append-only for the owner via file attributes (if supported). \begin{lstlisting}[style=cmd] $ chmod 600 notes.md $ sudo chattr +a notes.md \end{lstlisting} \nopagebreak[4] Mode \texttt{600} limits ordinary access to the owner. The \texttt{a} attribute separately makes the file append-only; it is a file attribute, not an owner-specific permission bit. Victor's filesystem supported it: \texttt{lsattr} showed \texttt{a}, and \texttt{stat} showed \texttt{600}. \end{enumerate} \subsection{Links and Find} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Verify whether \texttt{link-to-file1} is a symlink and show its target path. \begin{lstlisting}[style=cmd] $ [ -L link-to-file1 ] && readlink link-to-file1 \end{lstlisting} \nopagebreak[4] \texttt{-L} checks the link itself and \texttt{readlink} prints its stored target. Victor confirmed \texttt{src/file1.txt}. \item Find all regular files under the current tree larger than 40~KiB. \begin{lstlisting}[style=cmd] $ find . -type f -size +40k \end{lstlisting} \nopagebreak[4] The size test selects regular files larger than 40 KiB. Victor used the equivalent byte threshold \texttt{+40960c}, printing \texttt{./blob.bin} with 49,152 bytes. \item Find files modified in the last 10 minutes under \texttt{tmp/} and print their sizes. \begin{lstlisting}[style=cmd] $ find tmp/ -type f -mmin -10 -printf '%p %s\n' \end{lstlisting} \nopagebreak[4] \texttt{-mmin -10} selects recent modifications; \texttt{\%s} prints bytes. Victor's command returned no matches because no regular file under \texttt{tmp/} met that time window. \end{enumerate} \subsection{Processes and Job Control} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Show your processes in a tree view. \begin{lstlisting}[style=cmd] $ pstree -p "$USER" \end{lstlisting} \nopagebreak[4] \texttt{pstree -p} shows process relationships and PIDs for the specified user. Victor instead recorded his own processes with \texttt{ps -u} and \texttt{--forest}, exposing the shell, recording process, and child shell hierarchy. \item Start \texttt{sleep 120} in the background and show its PID. \begin{lstlisting}[style=cmd] $ sleep 120 & echo $! \end{lstlisting} \nopagebreak[4] The ampersand starts a background job; \texttt{\$!} is its PID. Victor captured and printed PID 2476 in his session; PIDs vary between executions. \item Send a TERM signal to all \texttt{sleep} processes owned by you (don't use \texttt{kill -9}). \begin{lstlisting}[style=cmd] $ pkill -TERM -u "$USER" -x sleep \end{lstlisting} \nopagebreak[4] \texttt{-u} restricts matches to the current user's processes and \texttt{-x} requires the exact name. Victor first checked for unrelated sleep processes, then terminated the test process. Waiting for it returned status 143 (128 + SIGTERM 15), and a final process search returned no matches. \item Show the top 5 processes by memory usage (one-shot, not interactive). \begin{lstlisting}[style=cmd] $ ps aux --sort=-%mem | head -n 6 \end{lstlisting} \nopagebreak[4] Descending memory percentage puts the largest consumers first; six output lines include one header and five processes. Victor used descending resident-memory size (RSS in KiB) instead; his largest displayed process was \texttt{snapd} at 41,208 KiB. \end{enumerate} \subsection{Archiving and Compression} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Create a gzipped tar archive \texttt{src.tgz} from \texttt{src/} with relative paths. \begin{lstlisting}[style=cmd] $ tar -czf src.tgz src/ \end{lstlisting} \nopagebreak[4] \texttt{-c} creates, \texttt{-z} compresses with gzip, and \texttt{-f} names the archive. The relative \texttt{src/} operand stores relative member paths. \item List the contents of \texttt{src.tgz} without extracting. \begin{lstlisting}[style=cmd] $ tar -tzf src.tgz \end{lstlisting} \nopagebreak[4] \texttt{-t} lists members without extraction. Victor's archive contained the two text files, their backups, and the \texttt{src/lib/} directory. \item Extract only \texttt{file2.txt} from \texttt{src.tgz} into \texttt{tmp/}. \begin{lstlisting}[style=cmd] $ tar -xzvf src.tgz -C tmp/ --strip-components=1 src/file2.txt \end{lstlisting} \nopagebreak[4] The named member limits extraction to one file, \texttt{-C} selects the destination, and stripping one path component produces \texttt{tmp/file2.txt}. Victor verified matching content with \texttt{cmp}. \end{enumerate} \subsection{Networking and System Information} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Show all listening TCP sockets with associated PIDs (no root assumptions). \begin{lstlisting}[style=cmd] $ ss -ltnp \end{lstlisting} \nopagebreak[4] The flags select listening TCP sockets, numeric addresses, and process details when permitted. Victor saw two loopback listeners on port 53; the process column was blank in his unprivileged invocation, so no associated PIDs are claimed. \item Print your default route (gateway) in a concise form. \begin{lstlisting}[style=cmd] $ ip route show default \end{lstlisting} \nopagebreak[4] Victor's default route used gateway \texttt{172.23.224.1} through \texttt{eth0}. This is a local environment result, not a fixed gateway for every machine. \item Display kernel name, release, and machine architecture. \begin{lstlisting}[style=cmd] $ uname -srm \end{lstlisting} \nopagebreak[4] The requested fields identify the kernel and architecture. Victor observed Linux, release \texttt{6.18.33.2-microsoft-standard-WSL2}, and \texttt{x86\_64}. \item Show the last 5 successful logins (or last sessions) on the system. \begin{lstlisting}[style=cmd] $ last -n 5 \end{lstlisting} \nopagebreak[4] Victor's last five available records were reboot/system-boot sessions rather than individual user logins. The record type is retained as shown; no successful user authentications are inferred. \end{enumerate} \subsection{Packages and Services (Debian/Ubuntu)} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Show the installed version of package \texttt{coreutils}. \begin{lstlisting}[style=cmd] $ dpkg-query -W -f='${Version}\n' coreutils \end{lstlisting} \nopagebreak[4] The query reads installed-package metadata. Victor also printed the package name and observed \texttt{coreutils 9.4-3ubuntu6.3}. \item Search available packages whose names contain \texttt{ripgrep}. \begin{lstlisting}[style=cmd] $ apt-cache search --names-only ripgrep \end{lstlisting} \nopagebreak[4] The search checks package names in the local catalog. It found \texttt{ripgrep}; availability in the catalog does not establish that the package is installed. \item Check whether service \texttt{cron} is active and print its status line only. \begin{lstlisting}[style=cmd] $ systemctl status cron | grep 'Active:' \end{lstlisting} \nopagebreak[4] Filtering the detailed status selects its Active line. Victor used \texttt{systemctl is-active cron}, a concise active-state query, and recorded \texttt{active}. \end{enumerate} \subsection{Bash and Scripting} \begin{enumerate}[label=\arabic*., leftmargin=*, resume] \item Write a one-liner that loops over \texttt{*.txt} in \texttt{src/} and prints: : . \textbf{Assumption:} the intended output is each file's name and line count, since the supplied problem PDF displays an incomplete output format. \begin{lstlisting}[style=cmd] $ for f in src/*.txt; do echo "$f: $(wc -l < "$f")"; done \end{lstlisting} \nopagebreak[4] For the stated line-count assumption, \texttt{wc -l} counts each file's lines and the loop prefixes its name. Victor's captured command instead printed filename and contents under a different interpretation of the incomplete prompt; Figure~\ref{Figure:HW2-J} documents that alternative. \item Write a command that exports CSV rows where \texttt{dept == "CS"} to \texttt{cs.txt} (exclude header). \begin{lstlisting}[style=cmd] $ awk -F, 'NR>1 && $3=="CS"' people.csv > cs.txt \end{lstlisting} \nopagebreak[4] The field separator is a comma; \texttt{NR>1} skips the header and field three selects CS. Victor verified that \texttt{cs.txt} contained \texttt{2,Linus,CS} and \texttt{4,Dennis,CS}. \item Create a variable \texttt{X} with value 42, print it, then remove it from the environment. \begin{lstlisting}[style=cmd] $ export X=42; echo "$X"; unset X \end{lstlisting} \nopagebreak[4] \texttt{export} adds the variable to the shell's exported environment; \texttt{unset} removes it. Victor printed \texttt{X=42}, then verified its absence using \texttt{printenv}. \end{enumerate} \section{Problem Set Execution Evidence} \label{Section:LinuxEvidence} These screenshots were supplied by Victor from his recorded September 27th session. They show actual commands and outputs, grouped by problem-set section. They supplement Payton's setup figures. Captions identify the question ranges; the explanations above distinguish equivalent commands. Empty output is retained where it is the observed result. \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/03-section-a-q01-q06.png} \caption{Q1--Q6: navigation and file operations. The moved file retains its original modification time, and the new notes file is empty.} \label{Figure:HW2-A} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/04-section-b-q07-q12.png} \caption{Q7--Q12: viewing and searching. The final command remains in follow mode at capture; Victor subsequently stopped it with Ctrl+C.} \label{Figure:HW2-B} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/05-section-c-q13-q16.png} \caption{Q13--Q16: text processing. Original text is retained in the backups, while the edited files total 31 bytes.} \label{Figure:HW2-C} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/06-section-d-q17-q20.png} \caption{Q17--Q20: permissions and attributes. Group execute was already set; the append-only attribute and owner-only notes-file access are verified.} \label{Figure:HW2-D} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/07-section-e-q21-q23.png} \caption{Q21--Q23: links and file searches. The recent-modification search returns no matches.} \label{Figure:HW2-E} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/08-section-f-q24-precheck.png} \caption{Q24 and precheck: Victor records his process tree and confirms no existing user-owned sleep processes before the demonstration.} \label{Figure:HW2-F1} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/09-section-f-q25-q27.png} \caption{Q25--Q27: background process, SIGTERM, exit status 143, and the five largest processes by resident-memory usage.} \label{Figure:HW2-F2} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/10-section-g-q28-q30.png} \caption{Q28--Q30: archive creation, member listing, selected extraction, and successful content comparison.} \label{Figure:HW2-G} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/11-section-h-q31-q34.png} \caption{Q31--Q34: sockets, route, kernel, and boot-session history. The unprivileged socket listing contains no process details.} \label{Figure:HW2-H} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/12-section-i-q35-q37.png} \caption{Q35--Q37: installed coreutils version, available ripgrep package, and active cron state.} \label{Figure:HW2-I} \end{figure} \begin{figure}[H] \centering \includegraphics[width=\linewidth,height=0.77\textwidth,keepaspectratio]{figures/13-section-j-q38-q40.png} \caption{Q38--Q40: Victor uses the filename-and-contents interpretation for Q38, then verifies the CS export and removal of X from the environment.} \label{Figure:HW2-J} \end{figure}