01. Linux for a Windows developer¶
Time: ~3 hours Prerequisites: none
1. In plain words¶
Linux is an operating system kernel plus a set of small programs that each do one job. Windows gives you one big integrated environment (Explorer, Visual Studio, the registry, services.msc). Linux gives you a toolbox: a shell to type in, hundreds of tiny commands, and a convention that everything is a file and text is the universal interface. Once you learn to chain those tiny commands together, you will do in one line what used to take a PowerShell script.
WSL2 (Windows Subsystem for Linux, version 2) is a real Linux kernel running inside a lightweight
virtual machine managed by Windows. It is not an emulator and not a compatibility layer. When you
type g++ in your Ubuntu terminal, a real Linux process runs on a real Linux kernel and the output
binary is a real Linux ELF executable. The only "magic" is that Windows and Linux can see each
other's files and that the VM starts in under a second.
Analogy: think of WSL2 as a second PC under your desk that shares your monitor and your C: drive
over a very fast network share. Anything you do on "that PC" is real Linux. Anything you do across
the share is slower.
2. The real thing¶
2.1 WSL2 mental model¶
+---------------------------- Windows 11 ---------------------------------+
| Explorer, Visual Studio, Docker Desktop, VS Code |
| |
| +------------------ Lightweight utility VM (Hyper-V) -----------------+ |
| | Real Linux kernel (Microsoft-built, e.g. 5.15 / 6.6) | |
| | Ubuntu 24.04 userland: bash, apt, gcc, cmake, systemd (optional) | |
| | Linux filesystem: ext4 inside a .vhdx file on your C: drive | |
| | /home/shakir/... <- FAST: native ext4 | |
| | /mnt/c/Users/... <- SLOW: 9P network filesystem to Windows | |
| +---------------------------------------------------------------------+ |
| \\wsl.localhost\Ubuntu-24.04\home\shakir <- Windows view of Linux FS |
+--------------------------------------------------------------------------+
Three rules that follow from this picture:
- Keep source code in the Linux filesystem (
/home/<you>/...). Compiling a project under/mnt/c/is routinely 5-20x slower (typical, from Microsoft's own WSL documentation and common experience) because everystat()andopen()crosses the 9P file-protocol boundary.git statuson a large repo under/mnt/ccan take seconds instead of milliseconds. - Edit from Windows if you like. Open the folder in VS Code with the "WSL" extension, or browse
\\wsl.localhost\Ubuntu-24.04\home\...in Explorer. The editor talks to the Linux side; the compiler runs natively. - Networking: WSL2 has its own IP (
ip addr show eth0), butlocalhostis forwarded both ways by default. A server listening on port 7000 in WSL is reachable from Windows atlocalhost:7000. The reverse (Linux reaching a Windows service) uses the Windows host IP from/etc/resolv.conf(nameserver line) or$(hostname).local.
Useful WSL commands from PowerShell:
wsl -l -v # list distros and WSL version
wsl --shutdown # stop the VM (frees RAM, resets networking)
wsl -d Ubuntu-24.04 # start a shell
wsl --update # update the kernel
Memory: WSL2 grows to 50% of host RAM by default. Cap it in C:\Users\<you>\.wslconfig:
2.2 The shell¶
Your default shell is bash. The prompt shakir@LAPTOP:~$ shows user, host, current directory
(~ is your home, /home/shakir). Core moves:
| Action | Command |
|---|---|
| Where am I | pwd |
| List | ls -la (-l long, -a include dotfiles, -h human sizes, -t by time) |
| Change dir | cd dir, cd .., cd - (previous), cd (home) |
| Make dir | mkdir -p a/b/c (-p creates parents, no error if exists) |
| Copy / move / delete | cp -r src dst, mv a b, rm -rf dir (no recycle bin: it is gone) |
| Show file | cat f, less f (q to quit, / to search), head -n 20 f, tail -f log (follow) |
| Find text | grep -rn "pattern" src/ |
| Find files | find . -name "*.cpp" |
| Help | man ls, ls --help, tldr ls (after sudo apt install tldr) |
| History | history, Ctrl-R (reverse search), !! (last command), sudo !! |
| Tab completion | Tab completes files, commands, and (with bash-completion) subcommands |
Quoting: single quotes '...' are literal; double quotes "..." expand $VAR and $(cmd).
* and ? are globs expanded by the shell before the program sees them. rm *.o is
expanded by bash into rm a.o b.o c.o; the program rm never sees the star.
2.3 Filesystem layout¶
There are no drive letters. One tree rooted at /.
/ root of everything
/home/shakir your home directory ($HOME, ~)
/etc system configuration (text files): /etc/passwd, /etc/hosts, /etc/ssh/
/bin, /usr/bin programs (ls, gcc, cmake). On Ubuntu 24.04 /bin is a symlink to /usr/bin
/usr/lib, /lib shared libraries (.so). /usr/lib/x86_64-linux-gnu/libstdc++.so.6
/usr/include system headers (stdio.h, c++/13/vector)
/usr/local things you install by hand (make install) - keeps apt and you separate
/opt third-party bundles (/opt/microsoft/...)
/var variable data: /var/log (logs), /var/lib (databases), /var/run
/tmp scratch, cleared on reboot
/proc virtual: kernel and process info as files (/proc/1234/status)
/sys virtual: devices and kernel parameters
/dev devices: /dev/null, /dev/zero, /dev/urandom, /dev/sda
/mnt/c your Windows C: drive (WSL only)
Paths use /. Case-sensitive: Main.cpp and main.cpp are different files. Hidden files start
with . (.bashrc, .git/). Extensions are convention only; the kernel decides executability by
a permission bit, not by .exe.
Important Windows difference: a file that is open can be deleted or replaced on Linux. The inode
stays alive until the last descriptor closes. This is why you can upgrade a running server's binary
and why rm of a log file does not free disk until the process closes it (see lsof in module 07).
2.4 Users, groups, permissions¶
Every file has an owner, a group, and nine permission bits: read/write/execute for owner/group/others.
$ ls -l tcpkv
-rwxr-xr-x 1 shakir shakir 48216 Oct 3 10:12 tcpkv
^^^ ^^^ ^^^
| | +-- others: r-x (read, execute)
| +------ group: r-x
+---------- owner: rwx
first char: - regular file, d directory, l symlink, c/b device, p pipe, s socket
chmod changes bits: chmod +x build.sh (add execute for all), chmod 644 file (rw-r--r--),
chmod 755 dir (rwxr-xr-x). Octal: r=4, w=2, x=1. chown shakir:shakir file changes owner.
For a directory, x means "may enter", r means "may list", w means "may create/delete entries".
root is the administrator (uid 0). You are not root. sudo cmd runs one command as root; your
password is cached for 15 minutes. Never run your normal shell as root; one typo in rm -rf and
the VM is gone. Services should run as a dedicated non-root user (module 11, systemd User=).
Windows ACLs are richer; Linux also has ACLs (setfacl) but almost nobody uses them for dev work.
There is no "Run as administrator" dialog: sudo is the equivalent.
2.5 Processes¶
A process has a PID, a parent PID, a user, a state, and open file descriptors. PID 1 is init
(systemd on Ubuntu; in WSL it is a small init unless you enable systemd in /etc/wsl.conf).
ps aux # all processes, BSD style
ps -ef # all processes, with parent PID
ps -o pid,ppid,stat,cmd -p 1234
pgrep -a tcpkv # find PIDs by name
top # live view; press 1 for per-core, M sort by memory, P by CPU, q quit
htop # nicer top; F5 tree view, F9 kill
kill 1234 # sends SIGTERM (15): "please exit"
kill -9 1234 # SIGKILL: kernel removes it, no cleanup, no core dump
kill -INT 1234 # SIGINT, same as Ctrl-C
killall tcpkv # by name
nohup ./server & # run in background, survive terminal close
jobs; fg; bg; Ctrl-Z # job control inside one shell
Signals are the Linux equivalent of Windows console control events plus structured exceptions in one mechanism. The ones you will meet:
| Signal | Number | Default action | When |
|---|---|---|---|
| SIGINT | 2 | terminate | Ctrl-C |
| SIGTERM | 15 | terminate | kill, systemd stop; your server should handle this gracefully |
| SIGKILL | 9 | terminate, cannot be caught | kill -9, OOM killer |
| SIGSEGV | 11 | core dump | invalid memory access (your access violation) |
| SIGABRT | 6 | core dump | abort(), failed assert, uncaught C++ exception |
| SIGPIPE | 13 | terminate | write to a socket/pipe whose reader closed. Servers ignore it. |
| SIGHUP | 1 | terminate | terminal closed; daemons reuse it for "reload config" |
| SIGCHLD | 17 | ignore | a child exited |
Exit status: echo $? after a command. 0 is success. 1-125 program-defined. 128+N means killed by
signal N (139 = 128+11 = SIGSEGV). Shell scripts and CI depend on this.
2.6 File descriptors, redirection, pipes¶
Every process starts with three open file descriptors (small integers indexing the kernel's open-file table): 0 stdin, 1 stdout, 2 stderr. Redirection rewires them before the program runs:
cmd > out.txt # stdout to file (truncate)
cmd >> out.txt # append
cmd 2> err.txt # stderr to file
cmd > all.txt 2>&1 # both to one file (order matters: redirect 1 first, then point 2 at 1)
cmd &> all.txt # bash shorthand for the above
cmd < input.txt # stdin from file
cmd > /dev/null 2>&1 # discard everything
cmd1 | cmd2 # stdout of cmd1 becomes stdin of cmd2 (a kernel pipe buffer, 64 KiB)
cmd1 |& cmd2 # pipe both stdout and stderr
cmd | tee log.txt # write to file and also pass through
Why 2>&1 order matters: redirections are applied left to right, and 2>&1 means "make fd 2 a
copy of what fd 1 is right now". cmd 2>&1 > f sends stderr to the terminal and stdout to f.
Here-doc and here-string:
2.7 The text-processing toolbox¶
These five commands cover 90% of daily log and code work.
grep — find lines matching a pattern.
grep -rn "TODO" src/ # recursive, show line numbers
grep -rni "error" /var/log/syslog # case-insensitive
grep -E "fail(ed|ure)" log # extended regex
grep -v "^#" config | grep -v "^$" # -v inverts: strip comments and blank lines
grep -c "GET" access.log # count matching lines
grep -l "include <thread>" -r . # list files only
grep -A3 -B1 "segfault" log # 3 lines after, 1 before
grep -rn --include="*.cpp" "mutex" . # restrict by glob
find — walk a tree and select files by attributes.
find . -name "*.o" -delete
find src -type f -name "*.cpp" | wc -l
find . -type f -size +10M
find . -mmin -30 # modified in last 30 minutes
find . -name "*.cpp" -exec clang-format -i {} \;
find . -name "*.cpp" -print0 | xargs -0 grep -l "pthread" # safe with spaces in names
xargs — turn stdin lines into command arguments.
pgrep tcpkv | xargs kill
find . -name "*.log" | xargs rm -f
cat hosts.txt | xargs -I{} ssh {} uptime # -I{} substitutes each line
find . -name "*.cpp" | xargs -P 8 -n 1 g++ -c # -P parallel, -n args per invocation
sed — stream editor; substitutions.
sed 's/foo/bar/' file # first occurrence per line, print to stdout
sed 's/foo/bar/g' file # all occurrences
sed -i 's/\bint32\b/std::int32_t/g' *.cpp # -i edit in place
sed -n '10,20p' file # print lines 10-20
sed '/^#/d' file # delete comment lines
sed -E 's/([0-9]+)ms/\1 ms/g' log # -E extended regex with capture groups
awk — a tiny language for column-oriented text. Fields are $1 $2 ..., $0 is the line,
NF field count, NR line number.
awk '{print $1}' access.log # first column
awk -F: '{print $1, $7}' /etc/passwd # -F sets separator
awk '$9 >= 500 {count++} END {print count}' access.log # count 5xx responses
awk '{sum += $3} END {print sum/NR}' latencies.txt # average of column 3
ps aux | awk '$3 > 50.0 {print $2, $11}' # PIDs using >50% CPU
awk '/ERROR/ && !/timeout/' app.log # pattern logic
Also: sort (-n numeric, -k2 by column 2, -u unique, -r reverse), uniq -c (count
duplicates; input must be sorted), cut -d, -f2 (column by delimiter), wc -l, tr a-z A-Z,
diff -u a b, head, tail, tee, column -t.
A real pipeline: top 10 IPs by request count from an access log.
2.8 Environment variables and PATH¶
Environment variables are inherited by child processes. PATH is a colon-separated list of
directories the shell searches for commands, left to right.
echo $PATH # /usr/local/bin:/usr/bin:/bin:...
which g++ # /usr/bin/g++ - first match in PATH
type cd # cd is a shell builtin
export CC=gcc CXX=g++ # export: visible to children
MY_VAR=1 ./prog # set only for that one command
env | sort # show all
unset MY_VAR
Persistent settings go in ~/.bashrc (run for every interactive shell) or ~/.profile (login
shells). After editing: source ~/.bashrc. Example additions:
export PATH="$HOME/.local/bin:$PATH"
export CMAKE_GENERATOR=Ninja
export EDITOR=vim
alias ll='ls -lah'
alias gs='git status'
Difference from Windows: there is no registry; there is no system-wide "Environment Variables" dialog that updates running programs. A variable set in one shell does not appear in another.
2.9 Package management with apt¶
apt is the Ubuntu package manager (think winget/chocolatey with a central, signed repository).
sudo apt update # refresh package index (does not install anything)
sudo apt install -y gdb # install
sudo apt remove gdb # remove (keep config); purge removes config too
apt search ninja # search
apt show cmake # details, version
apt list --installed | grep clang
dpkg -L cmake | head # which files a package installed
dpkg -S /usr/bin/g++ # which package owns a file
sudo apt autoremove # remove orphaned dependencies
Dev packages end in -dev and contain headers and link-time .so symlinks:
libpq-dev (PostgreSQL client), libssl-dev, libhiredis-dev. The runtime package (libpq5)
has only the shared object. A Docker runtime image needs only the runtime package (module 08).
2.10 SSH keys¶
SSH (Secure Shell) gives you a remote shell and is how Git talks to GitHub without passwords.
ssh-keygen -t ed25519 -C "rajaman.ar3@gmail.com" # accept defaults; set a passphrase
cat ~/.ssh/id_ed25519.pub # paste this into GitHub -> Settings -> SSH keys
ssh -T git@github.com # "Hi <user>! You've successfully authenticated"
eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519 # cache passphrase for this session
ssh user@host # remote shell
scp file user@host:/path/ # copy over ssh
ssh -L 5432:localhost:5432 user@host # port forward local 5432 -> remote 5432
~/.ssh/config saves typing:
Permissions matter: chmod 700 ~/.ssh; chmod 600 ~/.ssh/id_ed25519. SSH refuses keys that are
world-readable.
2.11 Windows concept -> Linux concept¶
| Windows | Linux | Notes |
|---|---|---|
C:\Users\you |
/home/you (~) |
|
C:\Program Files |
/usr/bin, /usr/lib, /opt |
programs and libs split by type, not by vendor |
C:\Windows\System32 |
/usr/lib, /lib |
|
%TEMP% |
/tmp |
|
| Registry | text files in /etc, ~/.config |
|
| Services (services.msc) | systemd units (systemctl) |
module 11 |
| Event Viewer | journalctl, /var/log |
|
| Task Manager | top, htop, ps |
|
taskkill /PID n /F |
kill -9 n |
|
dir, type, copy, del |
ls, cat, cp, rm |
|
where cmd |
which cmd |
|
findstr |
grep |
|
set VAR=x |
export VAR=x |
|
%PATH% with ; |
$PATH with : |
|
.exe |
no extension; execute bit | |
.dll / .lib |
.so / .a |
module 02 |
.pdb |
DWARF sections inside the ELF (-g) |
module 03 |
cl.exe, link.exe |
g++, ld (via g++) |
|
MSBuild, .sln, .vcxproj |
CMake, CMakeLists.txt, Ninja or Make |
module 04 |
| WinDbg, Visual Studio debugger | gdb, lldb |
module 07, 05_Memory_Debugging_RCA |
| Process Monitor | strace, ltrace |
module 07 |
| PerfView, VTune | perf, valgrind --tool=callgrind |
module 07 |
Dependency Walker, dumpbin /DEPENDENTS |
ldd, readelf -d |
module 02 |
dumpbin /SYMBOLS |
nm, objdump -t |
module 02 |
| Access violation (0xC0000005) | SIGSEGV | |
Minidump .dmp |
core file (core, coredumpctl) |
05_Memory_Debugging_RCA |
CreateProcess |
fork + exec |
module 11 |
WaitForSingleObject(hProcess) |
waitpid |
|
| HANDLE | file descriptor (int) | |
CloseHandle |
close |
|
| IOCP | epoll |
08_Networking |
CreateThread |
pthread_create / std::thread |
04_Concurrency |
| Critical section | pthread_mutex_t / std::mutex |
|
GetLastError() |
errno |
module 11 |
| Administrator | root via sudo |
|
\r\n line endings |
\n |
git config core.autocrlf input on WSL |
| Backslash paths, case-insensitive | forward slash, case-sensitive | |
| Winget / Chocolatey | apt |
|
| PowerShell | bash (or zsh, fish) | module 10 |
| Scheduled Tasks | cron, systemd timers |
|
| vcpkg / NuGet | vcpkg, Conan, or apt install lib*-dev |
module 12 |
3. Code¶
No C++ in this module; the "code" is shell. Create a scratch project and exercise the tools.
mkdir -p ~/scratch/m01 && cd ~/scratch/m01
cat > hello.cpp <<'EOF'
#include <cstdio>
int main(int argc, char** argv) {
std::printf("args=%d\n", argc); // prints to fd 1
std::fprintf(stderr, "to stderr\n"); // prints to fd 2
return argc > 1 ? 3 : 0; // exit status visible with $?
}
EOF
g++ -std=c++17 -Wall -Wextra -Werror -o hello hello.cpp
./hello; echo "status=$?"
./hello x y; echo "status=$?"
./hello > out.txt 2> err.txt; cat out.txt; cat err.txt
./hello 2>&1 | grep stderr # only stderr line, because the pipe carries both
ls -l hello # note the x bits
chmod -x hello; ./hello # "Permission denied": the bit, not the extension, decides
chmod +x hello
Watch a process and its file descriptors:
sleep 300 & # background job, prints its PID
PID=$!
ps -o pid,ppid,stat,cmd -p $PID
ls -l /proc/$PID/fd # 0,1,2 point at your terminal (/dev/pts/N)
cat /proc/$PID/status | head -12
kill $PID; wait $PID; echo "status=$?" # 143 = 128 + 15 (SIGTERM)
Log analysis pipeline on synthetic data:
for i in $(seq 1 1000); do
echo "$((RANDOM % 5 + 1)).example.com GET /api/$((RANDOM % 7)) $((RANDOM % 3 == 0 ? 500 : 200)) $((RANDOM % 900 + 10))ms"
done > access.log
awk '{print $1}' access.log | sort | uniq -c | sort -rn
awk '$4 == 500' access.log | wc -l
sed -E 's/([0-9]+)ms$/\1/' access.log | awk '{s += $5} END {printf "avg %.1f ms\n", s/NR}'
See code/m10_bash_patterns.sh for the scripting side (module 10).
4. Under the hood (senior-level)¶
Everything is a file descriptor. The shell implements cmd > out.txt with three syscalls:
fork() to create a child, in the child open("out.txt", O_WRONLY|O_CREAT|O_TRUNC) then
dup2(fd, 1) to make descriptor 1 refer to that file, then execve("cmd", ...). The program
never knows; it just writes to fd 1. A pipe is the same trick with pipe(fds) creating a kernel
buffer, dup2(fds[1], 1) in the writer and dup2(fds[0], 0) in the reader. Module 11 shows the C.
Permission bits are checked at open(), not at read(). Once you hold a descriptor, changing
the file's mode does not revoke it. This is why a server can open a privileged port or file as root
and then drop privileges with setuid().
Signals are delivered on return to user space. The kernel sets a bit in the target's pending
mask; the next time that thread transitions kernel -> user (syscall return, interrupt return), the
kernel runs the handler on the thread's stack. That is why a thread blocked in read() wakes up
with EINTR, and why signal handlers must be async-signal-safe (module 11).
/proc is a filesystem interface to the kernel. cat /proc/1234/maps is how gdb, perf
and top learn memory layout; /proc/1234/fd is how lsof works. Reading /proc/meminfo
costs one syscall and a few microseconds; no API to learn.
WSL2 file performance. The Linux ext4 filesystem lives in a .vhdx file; the Linux kernel
drives it with its own page cache and inode cache, so stat() is a few hundred nanoseconds. For
/mnt/c, each metadata operation becomes a 9P request to a Windows-side server (Plan 9 protocol
over a VM socket), context switch included; measured latencies are in the tens to hundreds of
microseconds. A cmake configure that stats thousands of files feels it immediately.
apt and shared libraries. apt install libpq-dev places /usr/include/postgresql/libpq-fe.h
and the symlink /usr/lib/x86_64-linux-gnu/libpq.so -> libpq.so.5. The link editor needs the
unversioned name; the dynamic loader at run time needs the versioned soname libpq.so.5. This
split is why a runtime image needs only libpq5 (module 02, module 08).
5. In production¶
- Logs are text, and the toolbox is the log viewer. On an incident you will do
journalctl -u tcpkv --since "10 min ago" | grep -c ERRORandtail -f /var/log/app.log | grep --line-buffered "txn=4471"long before you open any GUI. Learngrep -A/-B,awksums, andsort | uniq -cto reflex level. - Exit codes are the contract. CI treats a non-zero exit as failure. A test runner that
prints "FAILED" but returns 0 is a silent green build.
set -ein scripts (module 10) exists because of this. kill -9loses data. A banking server with an in-flight transaction needs SIGTERM, a handler that stops accepting, drains, flushes, and exits 0. systemd gives 90 seconds by default (TimeoutStopSec), then sends SIGKILL. Design for it (module 11).- Disk full with no big files. A deleted-but-open log file still consumes space.
lsof +L1lists them; restarting the writer frees the space. Classic 3 AM page. - Line endings. A bash script written in Notepad has
\r\n; bash reports/bin/bash^M: bad interpreter. Fix withsed -i 's/\r$//' script.shordos2unix, and setgit config --global core.autocrlf inputso Git normalises on commit. - Mapping to your current work: your RPC server on Windows runs as a service, logs to files and you read dumps in WinDbg. On Linux the same server is a systemd unit, logs to journald, and dumps to a core file read by gdb. The engineering is identical; only the tool names change. Interviewers like hearing that comparison.
6. Try it¶
- (easy) Create
~/projectsin the Linux filesystem. Timels -R /usr/include | wc -land then time the same on/mnt/c/Windows/System32withtime. Done when you can state the ratio and explain why the second is slower. - (easy) Write a one-line pipeline that prints the five largest files under
/usr/libwith human-readable sizes. Done when it runs and you can explain each stage. Hint:find -type f,du -h,sort -rh,head. - (medium) Start
sleep 1000 &, then from a second terminal find its PID withpgrep, inspect/proc/<pid>/status,/proc/<pid>/fd, and/proc/<pid>/maps. Send SIGTERM and verify the exit status is 143 in the first terminal. Done when you can explain the 143. - (medium) Given
/etc/passwd, print only usernames whose login shell is/bin/bash, sorted, usingawkandsort. Then do it again withgrepandcut. Done when both give identical output. - (hard) Write a pipeline that, given a file of lines
<timestamp> <latency_ms>, prints the p50, p95 and p99 latency. Done when it works on 10,000 random lines and you can explain how you computed the percentile index. Hint:sort -n,awkwithNRandint(), or collect into an array and index inEND. - (hard) Set up an SSH key, add it to GitHub, clone one of your repos over SSH into
~/projects, and setcore.autocrlf input. Done whenssh -T git@github.comgreets you andgit statusis clean after agit clone.
7. Interview questions¶
Q: What is WSL2 and how does it differ from WSL1?
WSL2 runs a real Linux kernel in a lightweight Hyper-V VM; syscalls hit a genuine kernel, so
Docker, perf and strace work. WSL1 translated Linux syscalls to NT calls in a compatibility
layer; faster for /mnt/c file access, but incomplete. For C++ development WSL2 is the right choice,
with sources kept in the Linux filesystem.
Q: Explain 2>&1 and why cmd 2>&1 > f behaves differently from cmd > f 2>&1.
Redirections apply left to right. 2>&1 copies the current target of fd 1 into fd 2. In
cmd > f 2>&1, fd 1 is already the file, so stderr follows it. In cmd 2>&1 > f, fd 2 copies the
terminal first, then fd 1 moves to the file; stderr stays on the terminal.
Q: What does exit status 139 mean? 128 + 11: the process was killed by signal 11, SIGSEGV. 134 is SIGABRT (128+6), 137 is SIGKILL (128+9), often the OOM killer in containers.
Q: Difference between SIGTERM and SIGKILL? SIGTERM can be caught: the process gets a chance to flush, close sockets and exit cleanly. SIGKILL cannot be caught or ignored; the kernel tears the process down immediately. systemd and Docker send SIGTERM, wait a grace period, then SIGKILL.
Q: Why can you delete a file that a process has open on Linux but not on Windows?
Linux separates the directory entry (name) from the inode (data). unlink removes the name; the
inode lives until the link count and open-descriptor count both reach zero. Windows by default takes
a sharing lock on open files. Consequence: on Linux a deleted log can still eat disk space.
Q: How does the shell find the program when you type g++?
It walks $PATH left to right and executes the first directory containing an executable named
g++. which g++ shows the winner. Builtins (cd, export) are handled by the shell and
never searched.
Q: What is the difference between libpq-dev and libpq5?
libpq5 is the runtime: the versioned shared object libpq.so.5. libpq-dev adds headers and
the unversioned libpq.so symlink the linker needs. Build images need -dev; runtime images need
only the runtime package.
8. Recap¶
- WSL2 is a real Linux kernel in a lightweight VM. Keep code under
/home, not/mnt/c. - One tree rooted at
/;/etcconfig,/usr/binprograms,/usr/liblibraries,/var/loglogs,/prockernel view,/tmpscratch. - Permissions are nine bits (rwx for owner/group/others) plus owner and group; execute bit decides what runs, not the extension.
sudofor one privileged command; never a root shell.- Processes:
ps,top,htop,killsends SIGTERM by default;kill -9is SIGKILL. - Exit status 0 is success; 128+N means killed by signal N.
- fd 0/1/2 are stdin/stdout/stderr;
>,2>,2>&1,|rewire them before the program starts. grep,find,xargs,sed,awk,sort | uniq -care the daily log and code toolbox.$PATHis searched left to right; persistent environment goes in~/.bashrc.apt installfor tools;-devpackages for headers;ssh-keygen -t ed25519for GitHub.