Linux Basic — Advanced Scripting Practice

2 minute read

Practice Exercises — Advanced Scripting

Solve these without temp files. Most should be one pipeline or a tight 5–10 line script.


Warm-up

  1. Templated config. Use a heredoc to generate /tmp/app.conf containing the current user, hostname, and date.
  2. No-expansion heredoc. Print a literal $PATH and a literal $(date) to a file without expansion.
  3. Indented heredoc. Use <<-EOF inside an if block so the body is tab-indented but stripped on output.
  4. Quick math. Compute pi = 22/7 to 6 decimal places using bc -l <<<.

Here-Strings

  1. Parse without subshell. Take the string "alice:1001:/home/alice" and split into user, uid, home using IFS=: and read <<<. Print all three after the read.
  2. Regex test. Validate that "192.168.1.10" looks like an IPv4 using grep -Eq and a here-string. Print valid or invalid.
  3. Pipe vs herestring. Show the difference: read into a variable using echo x | read v; echo "$v" and then read v <<< "x"; echo "$v". Explain why one is empty.

Process Substitution

  1. Diff two listings. diff <(ls dir1) against <(ls dir2). Create the dirs first with a few overlapping filenames.
  2. Common lines only. Use comm -12 <(sort fileA) <(sort fileB) to print lines present in both.
  3. Tee-split. Generate seq 1 1000 and split it: >(wc -l > /tmp/n) AND >(sha256sum > /tmp/h), sending raw output to /dev/null. Cat both result files.
  4. Live config drift (simulated). diff <(cat /etc/hostname) against <(echo "$HOSTNAME"). Should be identical.

Subshells & Grouping

  1. Isolated cd. Show pwd, run ( cd /tmp && pwd ), show pwd again. The outer pwd must not change.
  2. One redirect for many. Group three echo calls with { ; } and redirect once to out.log.
  3. Strict-mode block. Wrap a critical 3-command section in ( set -euo pipefail; ... ) so the surrounding script keeps lax settings.
  4. The pipe-loses-variable trap. Count files matching *.log using ls *.log | while read f; do ((n++)); done; echo "$n". Show why n is 0, then fix it using < <(...).

eval / coproc / exec

  1. Indirect variable (modern). Set name="foo" and foo="hello", then print hello using ${!name} (no eval).
  2. Script-wide log. Add exec > /tmp/run.log 2>&1 to the top of a script and confirm all subsequent echos appear in the log instead of the terminal.
  3. Open fd 3. Open fd 3 for writing to /tmp/three.log, send three lines to it with >&3, then close it.
  4. Wrapper handoff. Write a wrapper that exports MYAPP_ENV=prod then execs /usr/bin/env (so you can verify the env var in its output).
  5. Coprocess calculator. Start coproc BC { bc -l; }, send three expressions, read each answer, then close cleanly.

Stretch

  1. Heredoc-based SQL. Build a psql -d $DB <<SQL ... SQL block that takes a $user_id variable and selects from a table — make sure the variable expands but a literal $$ (dollar-quote) does not.
  2. Generate then patch. Create original.txt and modified.txt, then apply patch original.txt <(diff -u original.txt modified.txt) so original.txt ends up matching modified.txt.
  3. Multi-source env. Source two env files at once: source <(cat a.env b.env). Then prove both sets of vars are present.

Verification Checklist

  • No temporary files in any solution that uses process substitution
  • No eval unless explicitly required (and never with untrusted input)
  • All heredocs end with a flush-left delimiter
  • The exec > log test still leaves stderr captured (because of 2>&1)
  • The while read | pipe fix uses < <(...), not shopt -s lastpipe (unless you also disable job control)

Next chapter → Regular Expressions

Updated: