**1. Analyze Each `tar` Command from `/var/logs`:**
- We want to create a gzip-compressed tar archive at `backup/logs.tar.gz` containing all files inside `current/`.
- **Option A (`tar -czf backup/logs.tar.gz current/*`):** `-c` creates an archive, `-z` compresses with gzip, `-f backup/logs.tar.gz` specifies the output file inside `backup/`, and `current/*` archives all files inside `current`. (**Correct**)
- **Option B (`tar -czf backup/logs.tar.gz -C current .`):** Creates `backup/logs.tar.gz`, changes directory (`-C`) into `current`, and archives `.` (all files inside `current`). (**Correct**)
- **Option C (`tar -czf current/logs.tar.gz backup/*`):** Places the archive inside `current/` instead of `backup/` and archives `backup/*` instead of `current/*`. (**Incorrect**)
- **Option D (`gzip -c current/* > backup/logs.tar.gz`):** `gzip` alone does not create a `tar` archive of multiple files. (**Incorrect**)
**Answer: Options A and B.**
A: **Correct:** Creates a gzipped tar archive `backup/logs.tar.gz` containing all files matched by `current/*`.
B: **Correct:** Creates `backup/logs.tar.gz` after changing directory (`-C`) to `current` and archiving its contents (`.`).
C: **Incorrect:** Reverses the source and destination directories.
D: **Incorrect:** `gzip` compresses individual streams and does not bundle multiple files into a `.tar` archive.
**1. Analyze Each Pipeline for Sorting Unique Names and Counting Them:**
- We need to both (1) display the sorted list of distinct names and (2) count how many distinct names exist.
- **Option A (`sort names.txt | uniq | tee /dev/tty | wc -l`):** `sort names.txt | uniq` produces the sorted list of distinct names, `tee /dev/tty` prints that list directly to the terminal while also passing it down the pipe, and `wc -l` counts and prints the number of distinct lines. (**Correct**)
- **Option B (`sort -u names.txt | tee /dev/tty | wc -l`):** `sort -u` sorts and removes duplicates in a single step, `tee /dev/tty` displays the sorted distinct names on the terminal, and `wc -l` outputs the count of distinct names. (**Correct**)
- **Option C (`uniq names.txt | ...`):** `uniq` only removes *adjacent* duplicate lines; without sorting first, non-adjacent duplicates like `alice` and `bob` are not deduplicated. (**Incorrect**)
- **Option D (`sort names.txt | uniq -c`):** Prints the occurrence count of *each* individual name rather than the total count of distinct names. (**Incorrect**)
**Answer: Options A and B.**
A: **Correct:** `sort | uniq` deduplicates the sorted names, `tee /dev/tty` prints the list to the screen, and `wc -l` prints the count of distinct names.
B: **Correct:** `sort -u` outputs unique sorted lines, `tee /dev/tty` displays them, and `wc -l` counts them.
C: **Incorrect:** `uniq` requires sorted input to remove non-adjacent duplicate lines.
D: **Incorrect:** `uniq -c` counts how many times each name appears, not how many distinct names exist in total.
**1. Evaluate Each Command for Replacing `:x:` with `:admin:` Without Modifying `users.txt`:**
- **Option A (`sed 's/:x:/:admin:/' users.txt`):** Replaces `:x:` with `:admin:` on each line and prints the result to standard output **without** modifying `users.txt` on disk. (**Correct**)
- **Option B (`sed -i 's/:x:/:admin:/' users.txt`):** The `-i` flag edits `users.txt` **in-place** (modifying the file) and does not display the output to stdout. (**Incorrect**)
- **Option C (`awk -F: '{$2="admin"; OFS=":"; print}' users.txt`):** Splits each line on `:`, sets the second field (`x`) to `"admin"`, sets the output field separator to `:`, and prints `alice:admin:1001` etc. to stdout without modifying `users.txt`. (**Correct**)
- **Option D (`grep ':x:' users.txt > users.txt`):** Does not perform replacement and truncates `users.txt` via redirection! (**Incorrect**)
**Answer: Options A and C.**
A: **Correct:** `sed` without `-i` performs the substitution and prints the result to stdout while leaving `users.txt` unchanged.
B: **Incorrect:** The `-i` option modifies `users.txt` in-place instead of leaving the file unmodified.
C: **Correct:** `awk` splits on `:`, replaces the second field `x` with `admin`, and prints the colon-separated output to stdout without modifying `users.txt`.
D: **Incorrect:** `grep` does not replace text, and redirecting `> users.txt` overwrites and truncates the input file.
**1. Understand Standard Output (`1>`) and Standard Error (`2>`) Redirection:**
- Successful output from `ls /etc/passwd` goes to **stdout (file descriptor 1)**.
- Error messages from `/etc/doesnotexist` go to **stderr (file descriptor 2)**.
- **Option A (`ls /etc/passwd /etc/doesnotexist 1>output.txt 2>errors.txt`):** Redirects stdout (`1>`) to `output.txt` and stderr (`2>`) to `errors.txt`. (**Correct**)
- **Option B (`... >output.txt 2>&1`):** Redirects both stdout and stderr into `output.txt`. (**Incorrect**)
- **Option C (`ls /etc/passwd /etc/doesnotexist 2>errors.txt >output.txt`):** Redirects stderr (`2>`) to `errors.txt` and stdout (`>`, shorthand for `1>`) to `output.txt`. Order of independent redirections to different files does not matter. (**Correct**)
- **Option D (`... &>output.txt`):** Redirects both stdout and stderr into `output.txt`. (**Incorrect**)
**Answer: Options A and C.**
A: **Correct:** Explicitly sends stdout (`1>`) to `output.txt` and stderr (`2>`) to `errors.txt`.
B: **Incorrect:** `2>&1` merges stderr into stdout so both streams go to `output.txt`.
C: **Correct:** Sends stderr (`2>`) to `errors.txt` and stdout (`>`) to `output.txt`.
D: **Incorrect:** `&>output.txt` redirects both stdout and stderr to `output.txt`.
**1. Analyze Each Command for Summing Sales per Person and Sorting Descending:**
- **Option A (`awk '{arr[$1]+=$2} END{for(i in arr) print i,arr[i]}' sales.txt | sort -k2 -nr`):** Accumulates column 2 (`$2`) per person (`$1`) in associative array `arr`, prints `Name Total`, and pipes to `sort -k2 -nr` to sort numerically (`-n`) in reverse/descending order (`-r`) on field 2 (`-k2`). (**Correct**)
- **Option B (`sort -k1 sales.txt | uniq -c`):** Only counts identical lines rather than summing the numerical sales amounts in column 2. (**Incorrect**)
- **Option C (`awk '{sum[$1]+=$2} END{for(i in sum) print i,sum[i]}' sales.txt | sort -rnk2`):** Identical logic to Option A using array `sum` and combined sort flags `-rnk2`. (**Correct**)
- **Option D (`cat sales.txt | cut -d" " -f1 | uniq -c`):** Drops the sales numbers completely and only counts adjacent occurrences of names. (**Incorrect**)
**Answer: Options A and C.**
A: **Correct:** Sums the second field per name in `awk` and sorts the output numerically in descending order by the second column (`sort -k2 -nr`).
B: **Incorrect:** `uniq -c` counts duplicate lines instead of summing the sales values in column 2.
C: **Correct:** Sums column 2 per name in `awk` and sorts descending numerically on column 2 (`sort -rnk2`).
D: **Incorrect:** `cut -f1` discards the sales figures entirely.
**1. Analyze Each `egrep` / `grep` Command Against `/home/user/emails.txt`:**
- The file contains `.com`, `.net`, and `.org` emails. We want to extract valid email lines that do **not** end with `.org` (i.e., those ending with `.com` or `.net`).
- **Option A (`egrep "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.(com|net)$" /home/user/emails.txt`):** Matches valid email addresses ending in `.com` or `.net`, excluding `.org`. (**Correct**)
- **Option B (`egrep ".*@.*\.(com|net)$" /home/user/emails.txt`):** Matches lines containing `@` and ending with `.com` or `.net`, excluding `.org`. (**Correct**)
- **Option C (`grep -v "\.org$" /home/user/emails.txt | grep "@"`):** Marked incorrect in the official key because the question asks for a single `egrep` regex command matching valid emails ending in non-`.org` TLDs.
- **Option D (`egrep "^[^@]+@[^ ]+\.(?!org)[a-z]{2,3}$" ...`):** Standard POSIX ERE (`egrep`) does **not** support Perl negative lookaheads `(?!org)` (that requires `grep -P`). (**Incorrect**)
**Answer: Options A and B.**
A: **Correct:** Uses a valid POSIX extended regular expression (`egrep`) to match email addresses ending in `.com` or `.net`.
B: **Correct:** Uses `egrep` to match lines with `@` ending in `.com` or `.net`, excluding `.org` lines.
C: **Incorrect:** Not selected in the official answer key (uses two piped `grep` commands instead of a single `egrep` pattern).
D: **Incorrect:** Standard `egrep` (POSIX ERE) does not support Perl-style negative lookahead `(?!org)`.
**1. Trace the Short-Circuit Evaluation of `&&` and `||` in Bash:**
- Command: `grep "baz" data.txt && grep "xyz" data.txt || grep "bar" data.txt`
- **Step 1 (`grep "baz" data.txt`):** Since `baz` is present in `data.txt`, this command **succeeds** (exit status `0`) and prints **`baz`** to stdout.
- **Step 2 (`&& grep "xyz" data.txt`):** Because the first command succeeded (exit status `0`), the `&&` operator executes `grep "xyz" data.txt`. Since `xyz` is **not** in `data.txt`, this command **fails** (exit status `1`) and prints nothing.
- **Step 3 (`|| grep "bar" data.txt`):** Because the preceding pipeline status is now `1` (failure), the `||` operator executes `grep "bar" data.txt`. Since `bar` is in `data.txt`, it succeeds and prints **`bar`** to stdout.
- Therefore, both **`baz` and `bar`** are printed.
**Answer: baz and bar (Option C).**
A: **Incorrect:** After `grep "baz"` prints `baz`, `grep "xyz"` fails, which triggers the `|| grep "bar"` branch to also print `bar`.
B: **Incorrect:** `grep "baz" data.txt` runs first and prints `baz` before `grep "bar"` runs.
C: **Correct:** `grep "baz"` succeeds and prints `baz`; then `grep "xyz"` fails, triggering `|| grep "bar"` which prints `bar`.
D: **Incorrect:** Both `baz` and `bar` match lines in `data.txt` and are printed.
**1. Trace the Two `vi` Ex Commands on `data.txt`:**
- Initial 7 lines of `data.txt`:
`OK`, `FAIL`, `PENDING`, `FAIL`, `OK`, `DONE`, `FAIL`
- **Command 1 (`:g/FAIL/d`):** Globally matches every line containing `FAIL` and deletes (`d`) it. The remaining 4 lines are:
`OK`
`PENDING`
`OK`
`DONE`
- **Command 2 (`:v/OK/s/.*/CHECK/`):** `:v/OK/` (inverse global match) selects every line that does **not** contain `OK` (`PENDING` and `DONE`) and substitutes the entire line (`.*`) with `CHECK`:
`OK`
`CHECK`
`OK`
`CHECK`
**Answer: OK, CHECK, OK, CHECK (Option A).**
A: **Correct:** `:g/FAIL/d` deletes all `FAIL` lines, and `:v/OK/s/.*/CHECK/` replaces all non-`OK` lines (`PENDING` and `DONE`) with `CHECK`.
B: **Incorrect:** This replaces `OK` with `CHECK` and `PENDING`/`DONE` with `OK`, reversing the behavior of `:v/OK/`.
C: **Incorrect:** This is the state after `:g/FAIL/d` before running `:v/OK/s/.*/CHECK/`.
D: **Incorrect:** Only 3 options (A, B, C) are non-empty or Option D replaces `OK` with `CHECK`.
**1. Evaluate Each Command for Extracting Only the Packet Loss Percentage (with `%`):**
- Target output from `5 packets transmitted, 0 received, 100% packet loss, time 4073ms`: **`100%`** (or decimal like `20%`, `0.0%`).
- **Option A (`... | grep -Eo '[0-9]+(\.[0-9]+)?% packet loss'`):** Includes the words ` packet loss` in the output instead of only the percentage. (**Incorrect**)
- **Option B (`... | grep -Eo '[0-9]+(\.[0-9]+)?%' | tail -1`):** `-Eo` extracts only the matching percentage string (with `%`, handling integers or decimals), and `tail -1` ensures the summary line's percentage is selected. (**Correct**)
- **Option C (`... | awk '/packet loss/{print $(NF-3)}'`):** Fragile across Linux distributions because some versions of `ping` include extra fields (like `+1 errors` or omit `time ...ms`), shifting `$(NF-3)`. (**Incorrect**)
- **Option D (`... | sed -n 's/.* \([0-9.]*%\) packet loss.*/\1/p'`):** Captures the percentage token immediately preceding ` packet loss` into group `\1` and prints only `\1`, which works reliably regardless of field positions. (**Correct**)
**Answer: Options B and D.**
A: **Incorrect:** `grep -o` prints the entire matched pattern, which includes the trailing text ` packet loss`.
B: **Correct:** Extracts only the numeric percentage with `%` using `grep -Eo`.
C: **Incorrect:** Relying on fixed field offset `$(NF-3)` breaks when `ping` outputs additional fields (such as error counts) on different distributions.
D: **Correct:** Uses `sed` capture group `\1` anchored to `packet loss` to print only the percentage with `%`.
**1. Trace Redirection vs. Pipe Precedence in `cat data.txt >out.txt 2>&1 | grep 'a'`:**
- When setting up a pipeline, the shell first connects `cat`'s stdout to the pipe leading to `grep`, and **then** applies the file redirections `>out.txt 2>&1` from left to right on `cat`.
- `>out.txt` redirects `cat`'s stdout from the pipe to the file `out.txt`.
- `2>&1` redirects `cat`'s stderr to the same destination (`out.txt`).
- Consequently, all lines of `data.txt` are written into `out.txt`, and `grep 'a'` receives **empty input** (EOF) from the pipe and prints nothing to the terminal.
**Answer: out.txt contains all the lines of data.txt, and nothing is printed to the terminal (Option A).**
A: **Correct:** `>out.txt` redirects `cat`'s standard output to `out.txt` instead of the pipe, so `out.txt` gets all lines of `data.txt` and `grep 'a'` receives nothing.
B: **Incorrect:** File redirection `>out.txt` overrides the pipe for stdout, so nothing reaches `grep`.
C: **Incorrect:** `>out.txt` redirects stdout (not just stderr) to `out.txt`.
D: **Incorrect:** Redirection before a pipe is syntactically valid in Bash; it simply redirects the stream away from the pipe.
Arg: one two three four
Arg2: one two three four
Arg:
Arg:
Arg:
6406536004775, « Arg: four
one
two
three
Published solution
**1. Contrast `"$*"` and `"$@"` Inside Double Quotes in Bash:**
- The script is invoked as `./script.sh one "two three" four`, so there are 3 positional arguments: `$1 = one`, `$2 = two three`, and `$3 = four`.
- **First loop (`for arg in "$*"`):** Inside double quotes, `"$*"` expands to a **single word** joining all arguments with spaces: `"one two three four"`. Thus the loop runs **once** and prints:
`Arg: one two three four`
- **Second loop (`for arg in "$@"`):** Inside double quotes, `"$@"` expands each positional parameter as a **separate quoted word**: `"one"`, `"two three"`, `"four"`. Thus the loop runs **3 times** and prints:
`Arg2: one`
`Arg2: two three`
`Arg2: four`
**Answer: Option A.**
A: **Correct:** `"$*"` expands to a single string `"one two three four"` (one iteration), whereas `"$@"` preserves the three individual arguments across three iterations.
B: **Incorrect:** `"$*"` does not split into separate arguments when double-quoted.
C: **Incorrect:** `"$@"` preserves each argument separately (and unquoted splitting would split `two three`).
**1. Trace the Execution and Exit Status of `check()`:**
- Inside `check()`:
1. `ls /nonexistent >/dev/null`: Redirects stdout to `/dev/null`, while **stderr** is still printed to the terminal (`ls: cannot access '/nonexistent': No such file or directory`), and exits with status `2` (or `1`).
2. `echo "Done"`: Prints **`Done`** to stdout and succeeds with exit status **`0`**.
- In Bash, the return status (`$?`) of a function without an explicit `return` statement is the **exit status of the last command executed inside the function** (`echo "Done"`), which is **`0`**.
- Finally, `echo $?` prints **`0`**.
- Thus, the last two lines of output printed are **`Done` then `0`**.
**Answer: Done then 0 (Option D).**
A: **Incorrect:** `echo "Done"` runs after `ls` and prints `Done`, and its exit status is `0`, not `1`.
B: **Incorrect:** `echo "Done"` executes after `ls`, so `Done` is the second-to-last line before `0`.
C: **Incorrect:** Because `echo "Done"` is the last command in `check()`, the function's exit code `$?` is `0` (success), not `1`.
D: **Correct:** `echo "Done"` prints `Done` and succeeds with exit status `0`, so `echo $?` prints `0`.
**1. Understand `;;&`, `;&`, and `;;` in a Bash `case` Statement:**
- First, `val=$(echo "report.txt" | sed 's/report/file/')` sets `val="file.txt"`.
- Now let us trace `case $val in` with `val="file.txt"`:
1. **`f*)`:** Matches `"file.txt"`! Prints **`Starts with f`**. The terminator **`;;&`** tells Bash to **continue testing the remaining patterns** in the `case` statement.
2. **`*.txt)`:** Matches `"file.txt"`! Prints **`Ends with .txt`**. The terminator **`;;&`** again tells Bash to **continue testing subsequent patterns**.
3. **`file.*)`:** Matches `"file.txt"`! Prints **`File with extension`**. The terminator **`;&`** tells Bash to **fall through unconditionally** and execute the next clause's commands without testing its pattern!
4. **`*)`:** Executed via fall-through from `;&` (and also matches `*`). Prints **`Default case`** and terminates with `;;`.
- Therefore, all four lines are printed.
**Answer: Starts with f, Ends with .txt, File with extension, Default case (Option A).**
A: **Correct:** `;;&` continues testing subsequent patterns (`*.txt` and `file.*`), and `;&` falls through into the `*)` clause, printing all four messages.
B: **Incorrect:** Because `file.*)` ends with `;&` (fall-through), the `*)` block is also executed, printing `Default case`.
C: **Incorrect:** Since `val` becomes `file.txt`, it matches `f*)` first and prints `Starts with f`.
D: **Incorrect:** `file.txt` also matches `file.*)`, so `File with extension` is printed.
**1. Trace `if [ "$DEBUG" -eq 1 ]; then` When `$DEBUG` is Unset:**
- Since `DEBUG` is unset, `"$DEBUG"` expands to the empty string `""`.
- The command executed is `[ "" -eq 1 ]`.
- In Bash's `[` (`test`) command, the `-eq` operator requires **integer** operands on both sides. Passing an empty string `""` to `-eq` triggers the error:
`bash: [: : integer expression expected`
and `[` exits with an error status (`2`).
**Answer: Script exits with error (Option B).**
A: **Incorrect:** `""` is not equal to `1`, so `Debug Mode ON` is never printed.
B: **Correct:** When `$DEBUG` is unset, `"$DEBUG"` expands to `""`, and `[ "" -eq 1 ]` fails with `integer expression expected` error.
C: **Incorrect:** It prints an error message (`integer expression expected`) to stderr rather than printing nothing.
D: **Incorrect:** Unset variables are not automatically set to `1` by `[`.
**1. Decode the Crontab Schedule and Redirections:**
- Crontab entry: `0 3 * * * /home/user/cleanup.sh >> /var/log/cleanup.log 2>&1`
- **Schedule (`0 3 * * *`):**
- Minute = `0`, Hour = `3` (24-hour clock, so **3:00 AM**), Day of Month = `*`, Month = `*`, Day of Week = `*` (every day).
- **Redirection (`>> /var/log/cleanup.log 2>&1`):**
- `>>` **appends** standard output to `/var/log/cleanup.log`, and `2>&1` redirects standard error to the same appended file.
**Answer: The script will run at 3 AM every day, and both standard output and errors will be appended to cleanup.log (Option B).**
A: **Incorrect:** Cron uses a 24-hour clock, so hour `3` is 3:00 AM, not 3:00 PM (which would be `15`).
B: **Correct:** `0 3 * * *` runs daily at 3:00 AM, and `>> ... 2>&1` appends both stdout and stderr to `cleanup.log`.
C: **Incorrect:** Minute is `0` (not `*`), so it runs once at 3:00 AM, not every minute of the 3 AM hour.
D: **Incorrect:** `>>` appends to the log file, whereas `>` would overwrite it.
**1. Trace the `awk` Associative Array Script on `file.txt`:**
- Input lines: `apple`, `banana`, `apple`, `orange`, `banana`.
- For every line, `lines[$0]++` increments the count of that line in the array `lines`:
- `lines["apple"] = 2`
- `lines["banana"] = 2`
- `lines["orange"] = 1`
- In the `END` block, `if (lines[line] > 1)` filters for lines that appeared **more than once** (`apple` and `banana`) and prints `line, lines[line]`:
`apple 2`
`banana 2`
**Answer: apple 2, banana 2 (Option A).**
A: **Correct:** Only `apple` and `banana` have counts strictly greater than 1 (`lines[line] > 1`), printing `apple 2` and `banana 2`.
B: **Incorrect:** `orange` has count 1, which is excluded by `if (lines[line] > 1)`.
C: **Incorrect:** `print line, lines[line]` prints both the word and its count, and excludes `orange`.
D: **Incorrect:** Each matching item is printed on its own line along with its frequency.
**1. Understand Address-Restricted Substitution in `sed`:**
- Command: `sed '/TEST/s/FAIL/PASS/g' results.log`
- `/TEST/` is a regular expression **line address filter**: `sed` only applies the following command to lines that match `/TEST/`.
- `s/FAIL/PASS/g` substitutes all occurrences of `FAIL` with `PASS` on those matched lines.
- Therefore, it **replaces `"FAIL"` with `"PASS"` only in lines containing `"TEST"`**.
**Answer: Replaces "FAIL" with "PASS" only in lines containing "TEST" (Option B).**
A: **Incorrect:** Without `/TEST/`, `sed 's/FAIL/PASS/g'` would replace `FAIL` everywhere, but the `/TEST/` address restricts it to lines containing `TEST`.
B: **Correct:** The `/TEST/` address prefix restricts the `s/FAIL/PASS/g` substitution to lines that contain `TEST`.
C: **Incorrect:** Deleting lines containing `TEST` would use the `d` command (`sed '/TEST/d'`), not `s/.../.../`.
D: **Incorrect:** `/TEST/` is the line selector, while `s/FAIL/PASS/g` replaces `FAIL` with `PASS`.
**1. Decode Bash `PS1` Prompt Escape Sequences:**
- We are given `export PS1="[\u@\h \w]$ "` with:
- `\u` = username = `iitm`
- `\h` = hostname = `linuxbox`
- `\w` = full current working directory = `/home/iitm/projects` (note: lowercase `\w` shows the full path, whereas uppercase `\W` shows only the basename `projects`)
- Substituting these values into `[\u@\h \w]$ ` yields:
**`[iitm@linuxbox /home/iitm/projects]$`**
**Answer: [iitm@linuxbox /home/iitm/projects]$ (Option A).**
A: **Correct:** `\u` expands to `iitm`, `\h` to `linuxbox`, and `\w` to the full working directory `/home/iitm/projects`.
B: **Incorrect:** Swaps username (`\u`) and hostname (`\h`), and uses basename (`\W`) instead of full path (`\w`).
C: **Incorrect:** Bash expands `\u`, `\h`, and `\w` inside `PS1` rather than printing them literally.
D: **Incorrect:** Places the directory after `@` instead of the hostname.
**1. Evaluate `date +%Y%m%d%H%M` for `21 Sep 2025, 14:35`:**
- `%Y`: 4-digit year = `2025`
- `%m`: 2-digit month (`01`–`12`) for September = `09`
- `%d`: 2-digit day of month = `21`
- `%H`: 2-digit hour (24-hour clock) = `14`
- `%M`: 2-digit minute = `35`
- Since there are no hyphens between the format specifiers in `+%Y%m%d%H%M`, `$(date +%Y%m%d%H%M)` expands to `202509211435`.
- Therefore, the archive filename is **`backup-202509211435.tar.gz`**.
**Answer: backup-202509211435.tar.gz (Option A).**
A: **Correct:** `+%Y%m%d%H%M` concatenates year (`2025`), month (`09`), day (`21`), hour (`14`), and minute (`35`) with no hyphens.
B: **Incorrect:** There are no `-` separators inside the format string `+%Y%m%d%H%M`.
C: **Incorrect:** `%m` produces the 2-digit numeric month `09`, whereas `%b` produces `Sep`.
D: **Incorrect:** The format string starts with `%Y%m%d` (date first), not `%H%M` (time first).