Linux Commands & Shell Skills
Bash Scripting: From 'works on my box' to Production
Bash earns its slot when a task is glue: orchestrate commands, wrangle simple text, and stay entirely on the box. Its industry reputation comes from the landing, not the idea: untested pipelines shipped into cron on a server where one variable was unset or one filename had a space. The discipline is mechanical and cheap, and it has four parts: strict mode, quoting, shellcheck, and logging the way ops will read it later.
Key points
- Every serious script opens with set -euo pipefail: unset variables fail, command failures stop the script, pipeline lies surface; without it, errors pass silently until they reach production.
- Quote variables and command substitutions: "$var" and "$(cmd)"; word splitting on spaces is the all-time classic, and the IFS fiddling some sites recommend is a bug you are choosing to remember.
- Brace expansion happens before variables: rm -rf "${CLEANUP:?}"/{a,b} with CLEANUP unset expands differently than intended and removes things you meant to keep; ${VAR:?} checks are the rm-safety idiom worth learning once.
- shellcheck earns its place on every change: it catches unquoted globs, unreachable code, and 'for f in $(ls)' patterns that eat filenames with spaces; run it in CI and the bugs stop reaching cron.
- Temp work and cleanup are paired: TMP=$(mktemp -d), trap 'rm -rf "$TMP"' EXIT, and no orphaned scratch dirs plus no 'if error then remove' sprinkles on every branch.
- Read loops the safe way: while IFS= read -r -d '' f handles filenames with newlines and spaces via find -print0; 'for f in $(ls)' is the bug shellcheck flags and old scripts everywhere still carry.
- Exit codes and logs speak to ops: echo failures to stderr (>&2) with a stage name, exit nonzero on real failure, and let cron's mail or journald show you the one line you actually need at 3 a.m.
- Escalate early: JSON parsing, three-plus levels of nesting, HTTP calls, or any stateful logic belongs in Python or awk; bash bent into a general-purpose language is where its reputation was earned.
Field note
Our brace-expansion scar: rm -rf "${CLEANUP}"/{a,b} with CLEANUP unset expanded exactly the way the shell, not the intent, wanted. Every path like that now carries the ${VAR:?} guard, and nobody has paid that bill twice.
Frequently asked questions
#!/bin/bash or #!/usr/bin/env bash?
env wins across containers and macOS installs where bash lives elsewhere; the shebang matters less than set -euo pipefail being actually present and shellcheck passing on every change.
My script works manually but fails in cron. Why?
Cron runs with a bare environment: PATH is short, there is no login profile, and relative paths point at the wrong home. Use absolute paths, set PATH explicitly, and keep bash -x replay for debugging.
Bash or Python for server tasks?
Bash for pipelines that mostly orchestrate existing system tools and stay small; Python for structured data, APIs, and error handling that must survive on-call. Forcing bash to play Python is how incidents get names.
How do I script deletions safely?
Quote every variable, target only mktemp-produced or explicitly configured paths, run with a dry-run mode that prints what it would remove, and let a ${VAR:?} guard veto unset variables before rm sees them.
How Kinetikatech helps with linux commands & shell skills
You shouldn't have to become an expert in linux commands & shell skills: The commands and scripting habits that decide whether an administrator operates a server or fights it: search, transform, transfer, and supervise text and processes with the tools that live in every base install. That's exactly what Linux Server Security and Server Management is for, setup, hardening, monitoring, and a human on call day and night.