Linux Tools for Placement Preparation
A strong Linux answer names the tool that observes the right layer, explains what its output means, and states the safety boundary. This chapter is a compact, practical companion to the deeper Linux material in this book.
Safety first: examples that use
sudo,kill,rm, mounts, packet capture, firewall changes, or remote access can affect a real system. Try them in a disposable environment, quote paths, and inspect a command before adding a destructive action.
A question-driven workflow
flowchart TD
S["Start with a symptom"] --> Q1{"What is the first useful boundary?"}
Q1 -->|"Files or text"| F["find, grep, rg, sed, awk"]
Q1 -->|"Process or CPU"| P["ps, top, pgrep, strace, perf"]
Q1 -->|"Disk or mount"| D["df, du, lsblk, findmnt"]
Q1 -->|"Network path"| N["ip, ss, dig, ping, tcpdump"]
Q1 -->|"HTTP API"| H["curl -v and curl -w"]
F --> C["Collect evidence"]
P --> C
D --> C
N --> C
H --> C
C --> R["Change one variable and re-measure"]
Use the smallest tool that answers the question. For example, ss answers
which sockets exist; it does not prove that an HTTP handler is healthy. Pair
it with curl, application logs, or a trace.
Safe shell building blocks
Quote data and preserve filenames
Shell parsing performs expansions before a command runs. Quote variables unless you intentionally want word splitting or glob expansion:
file="report with spaces.txt"
printf '%s\n' "$file" # one argument, safe
rm -- "$file" # -- ends options; still verify first
For lists of arbitrary Unix filenames, use NUL delimiters instead of newline:
find . -type f -name '*.log' -print0 |
while IFS= read -r -d '' file; do
printf '%s\n' "$file"
done
find -exec ... {} + is often simpler and avoids a separate xargs
process. If you use xargs, pair find -print0 with xargs -0; plain
xargs splits on whitespace and can corrupt names containing spaces or
newlines.
Exit status and pipelines
set -euo pipefail
if ! output=$(some_command); then
printf 'command failed\n' >&2
exit 1
fi
set -e is not a complete error policy: understand conditionals, command
substitution, and pipeline status. Use pipefail when a producer failure
must make the pipeline fail, and handle expected non-zero statuses explicitly.
File and text tools
find: query a directory tree
What it does: walks a hierarchy and evaluates predicates and actions.
find src -type f -name '*.md' -print
find . -type f -size +100M -printf '%s %p\n' | sort -nr | head
find . -type f -mtime -1 -name '*.log' -exec grep -Hn 'ERROR' {} +
find . -type f -name '*.tmp' -print # inspect before replacing -print
Useful options include -type, -name/-iname, -path, -mtime, -size,
-user, -maxdepth, -xdev, -prune, -printf, and -exec. Remember
that -a binds more tightly than -o; parenthesize alternatives:
find . -type f \( -name '*.c' -o -name '*.h' \) -print
Use -print0 for arbitrary names. In security-sensitive directories,
prefer -execdir or a carefully reviewed -exec; a producer-to-consumer
pipeline can have a time-of-check/time-of-use race.
Interview question: Why can find . -name *.c fail? The shell may expand
*.c before find sees it; quote the pattern as '*.c'.
xargs: turn input into arguments
printf '%s\0' *.json | xargs -0 -r jq empty
find . -type f -name '*.py' -print0 | xargs -0 -r -n 1 python -m py_compile
Important options are -0 for NUL input, -r to avoid an empty invocation
(GNU extension), -n for a maximum number of arguments, -P for bounded
parallelism, -I for replacement, and --show-limits for ARG_MAX
inspection. Do not use ls | xargs for filenames, and do not use -P when
order, shared state, or rate limits make parallel execution unsafe.
grep and rg: search text
grep -RIn --include='*.c' 'TODO' src
grep -E '^(WARN|ERROR):' app.log
grep -F 'literal [text]' file.txt
rg -n --glob '*.py' 'except\s+[^:]+:' .
rg --files -g '*.md' | sort
grep -F treats the pattern literally; -E enables extended regular
expressions; -i, -n, -C, -l, -L, -v, and -w are common filters.
rg (ripgrep) is usually faster for a project because it respects ignore
files and searches recursively by default. grep is more ubiquitous in
minimal environments.
A command returning status 1 can mean “no match,” not operational failure; handle that distinction in scripts.
sed, awk, cut, sort, uniq
sed -n '1,80p' config.ini
sed -E 's/[[:space:]]+$//' input.txt
awk -F: '{ print $1, $3 }' /etc/passwd
cut -d, -f1,3 records.csv
sort -t, -k3,3n records.csv
sort names.txt | uniq -c | sort -nr
sedis a stream editor: substitutions, selected ranges, and small transformations. Use a version-controlled file or a backup when usingsed -i.awkis useful when records have fields and a condition/action model. Set-Fexplicitly for delimited data; it is not a full CSV parser.cuthandles simple fixed delimiters; use a CSV-aware tool for quoted CSV.sortmust usually precedeuniq;uniqonly collapses adjacent equal lines. Usesort -nfor numeric andsort -hfor human-readable values.
head, tail, and less reduce the amount of data you inspect:
tail -F app.log
tail -n 200 app.log | grep -E 'WARN|ERROR'
less +G app.log
A maintainable pipeline
find logs -type f -name '*.log' -print0 |
xargs -0 -r grep -hE 'status=[45][0-9]{2}' |
sed -E 's/.*status=([0-9]{3}).*/\1/' |
sort | uniq -c | sort -k2,2n
Explain each stage and its assumptions in an interview. If input is large,
consider a single awk pass instead of spawning multiple processes.
Processes and system calls
ps, top, htop, pgrep, pkill, kill
ps -eo pid,ppid,stat,etime,%cpu,%mem,comm --sort=-%cpu | head
ps -T -p "$PID" # threads for one process
pgrep -a -f 'worker --queue'
pkill -TERM -f 'worker --queue' # inspect the match first
top -H -p "$PID" # per-thread view
kill -TERM "$PID" # request graceful shutdown
kill -KILL "$PID" # last resort; cannot be handled
ps is a snapshot; top/htop sample repeatedly. STAT=Z indicates a
zombie: the process has exited, but its parent has not reaped it. A zombie is
not consuming CPU; find the parent and fix its wait/supervision logic.
D commonly indicates uninterruptible sleep, often waiting on I/O.
Signals are requests with different semantics: TERM permits cleanup,
HUP is application-dependent, INT resembles Ctrl-C, and KILL is
non-catchable. Match by PID rather than a broad command-line pattern where
possible.
Interview question: Why can CPU be high while a process is not “stuck”?
It may be a hot loop, lock contention, GC, or kernel time; correlate ps,
per-thread views, and perf/tracing instead of inferring from one sample.
lsof: map open resources to processes
lsof -p "$PID"
lsof -iTCP:8080 -sTCP:LISTEN
lsof +L1 # open files whose directory entry is gone
lsof helps answer “why cannot I unmount this filesystem?” or “which process
owns this port?” It may need elevated privileges for complete visibility.
An unlinked file can continue consuming disk until its last file descriptor is
closed; lsof +L1 is a useful diagnostic.
strace: observe system-call boundaries
strace -f -tt -T -o trace.log ./program
strace -f -e trace=file -p "$PID"
strace -c -f ./program
Use -e trace= to narrow the question (file, network, process, or
specific calls), -f for descendants, -p to attach, -c for a summary,
and -T for syscall duration. Tracing adds overhead and can change timing;
never treat a trace as a production benchmark. For lower-overhead aggregate
observability, compare perf, tracepoints, ftrace, or eBPF.
time and perf
/usr/bin/time -v ./program
perf stat -e cycles,instructions,cache-misses ./program
perf record -g -- ./program
perf report
Shell time output varies; /usr/bin/time -v gives resource details on
many Linux distributions. perf stat counts events, while perf record
collects samples for a profile. Interpret counters relative to workload and
CPU; a cache-miss count without a baseline is not a diagnosis.
Disk, filesystems, and mounts
df -hT # filesystem capacity and type
du -xhd1 /var | sort -h # directory usage, stay on one filesystem
lsblk -f # block devices, filesystems, labels
findmnt --df # mounted filesystems and capacity
findmnt / # which mount supplies a path
dfreports filesystem-level free space.duwalks directory entries and reports apparent/allocated usage depending on options; it can disagree withdfwhen deleted files remain open.lsblkdescribes block-device topology, not application disk usage.findmntanswers mount and filesystem questions without parsingmountoutput.
Interview question: Why does df show less free space than du suggests?
Open-but-unlinked files, reserved blocks, filesystem metadata, snapshots, or
other mounts can account for the difference. Check lsof +L1, mount points,
and filesystem-specific tools.
Avoid parsing ls or df output when a machine-readable interface exists;
use /proc, /sys, findmnt, or a documented command option.
Networking tools
ip and ss
ip -br address
ip route get 1.1.1.1
ip -s link show dev eth0
ss -ltnp
ss -tan state time-wait
ss -s
ip covers links, addresses, routes, and neighbours. ss reads socket state
and is the modern replacement for most netstat use cases. LISTEN is a
server socket; TIME-WAIT is a normal TCP lifecycle state after close; many
TIME-WAIT sockets may indicate connection churn, but are not automatically a
bug. Use -p only where permissions allow process information.
curl and wget
curl --fail-with-body --silent --show-error \
--connect-timeout 3 --max-time 10 https://example.com/health
curl -sS -o /dev/null -w 'status=%{http_code} ttfb=%{time_starttransfer}\n' \
https://example.com/
curl -v --http1.1 https://example.com/
wget --server-response --spider https://example.com/
curl -v exposes request/response and TLS negotiation details; -I sends a
HEAD request and is not equivalent to a GET for every server. Use --fail
variants in automation so HTTP 4xx/5xx become failures. Do not put secrets in
URLs because they can leak through shell history and logs; prefer headers or
.netrc with appropriate permissions.
wget is convenient for recursive or resumable downloads; curl is often
better for API testing and precise request construction.
dig, nslookup, ping, traceroute, mtr
dig +short A example.com
dig @1.1.1.1 example.com MX +noall +answer
nslookup -type=AAAA example.com
ping -c 4 example.com
traceroute -n example.com
mtr --report --report-cycles 10 example.com
DNS success does not prove TCP or HTTP health. ping uses ICMP, which may be
filtered; a failed ping is not proof that a service is down. traceroute may
show * because an intermediate hop does not reply, not because the final
path is broken. Test the relevant transport and port with ss, nc, or
curl when appropriate.
tcpdump
sudo tcpdump -ni any 'host 10.0.0.5 and tcp port 443'
sudo tcpdump -ni eth0 -w capture.pcap 'udp port 53'
tcpdump -nnr capture.pcap 'tcp[tcpflags] & tcp-syn != 0'
Use -n to avoid reverse-DNS noise, -i to choose an interface, -w to
save a pcap, and a narrow BPF filter to reduce capture volume. Captures can
contain credentials or personal data; protect them and delete them according
to policy. A packet capture shows what crossed the observation point, not what
an endpoint intended to send.
Developer and workflow tools
git
git status --short --branch
git log --oneline --decorate -10
git diff --check
git grep -n 'pattern' -- '*.c' '*.h'
git worktree add ../review feature/topic
Use git diff --check for whitespace errors, git grep for tracked source,
and git worktree when two branches must be inspected without repeatedly
checking files in and out. Never put tokens or passwords in remotes, commits,
logs, or command output.
ssh, scp, and rsync
ssh -o ConnectTimeout=5 user@host 'uname -a; uptime'
scp ./build/app user@host:/tmp/app
rsync -aHAX --dry-run ./data/ user@host:/srv/data/
rsync -aHAX --delete ./data/ user@host:/srv/data/ # review dry-run first
Use host keys, least-privilege accounts, and explicit identity files. scp
is simple copying; rsync transfers deltas and can preserve metadata. A
trailing slash changes whether the source directory itself or only its
contents are copied. --delete is powerful and should be preceded by a
reviewed --dry-run.
jq, make, and tmux
jq -r '.items[] | select(.enabled) | .name' response.json
make -j"$(nproc)" test
make -n deploy # print commands without executing
tmux new -s incident
tmux attach -t incident
jq is safer than grep for JSON because it understands structure. make -n
previews a rule; -j can expose races in a build or overwhelm a host, so use
an appropriate job count. tmux keeps a long-running session alive across an
SSH disconnect; do not assume a detached session is a monitoring or
supervision system.
Incident recipes
“The service is unreachable”
getent hosts api.example.com
ip route get 203.0.113.10
ss -ltnp | grep ':8443'
curl -v --connect-timeout 3 https://api.example.com:8443/health
This separates DNS, routing, local listening, TCP/TLS, and application health.
If the local service is listening, use tcpdump at the relevant interface and
check firewall and proxy policy before changing configuration.
“The disk is full”
df -hT
sudo du -xhd1 / | sort -h | tail
sudo lsof +L1
findmnt --df
Do not delete files based only on a large du line. Confirm the filesystem,
mount boundary, open deleted files, snapshots, and retention policy.
“The process is slow”
ps -o pid,ppid,stat,wchan:32,%cpu,%mem,etime,cmd -p "$PID"
strace -f -e trace=file,network -p "$PID"
/usr/bin/time -v command
perf record -g -- command
Start with a hypothesis and a short observation window. Stop tracing when you have enough evidence; instrumentation itself can alter latency.
Interview checklist
- Explain why
find -print0 | xargs -0is safer thanfind | xargs. - Distinguish a process, thread, file descriptor, socket, and inode.
- Explain
SIGTERMversusSIGKILL, and diagnose a zombie process. - Compare
df,du,lsblk, andfindmnt. - Explain why
pingcan fail while HTTPS succeeds. - Interpret
LISTEN,ESTABLISHED,CLOSE-WAIT, andTIME-WAIT. - State what
strace,perf, ftrace, and eBPF observe and their overhead. - Explain why quoting,
--, NUL delimiters, and least privilege matter. - Design a reproducible evidence-collection command without leaking secrets.
References
The command descriptions and safety notes were checked against primary or project-maintained documentation on 2026-08-12: