Setup scripts you can run twice without fear
Updated

Idempotent scripts check state before changing it: the second run is a harmless no-op, not a second disaster.
Setup scripts run twice. Someone retries after a failure, a pipeline replays a step, a teammate runs it just in case. A script that assumes a clean slate corrupts on the second run: duplicate entries, doubled permissions, appended blocks twice.
Check, then act
Every change starts with a check. User exists? Directory correct? Line already present? The check decides; the change only executes on a gap.
Desired state, not steps. Describe the end state and converge toward it. Step lists without checks are one-shot fireworks.
Prove the second run. Fixture, run, run again, compare. The second log should read like a calm confirmation, mostly skipped, nothing changed.
Worked example: a fictional onboarding script
The context below is fictional. Fictional script onboard.sh (fictional) creates a user, a directory tree and three config lines. The second run duplicates the config lines and fails on the existing user.
The rewrite checks each resource first: user present means skip, directory correct means skip, lines present means skip. The second run changes nothing and says so. Retries become safe by construction.
Checklist: a script safe to rerun
- Every mutation guarded by a state check.
- Second run on a fixture changes nothing.
- Output states what was skipped and why.
- Partial failure resumes without manual cleanup.
Related reading
- Hands on: Harmless Second Run of the Setup Script.
- The shell companion: Shell scripts that survive spaces.
Straight answers
Frequently asked questions
What does idempotent mean here?
Running the script twice gives the same result as running it once. The second run detects existing state and changes nothing.
What is the cheapest pattern?
Check-then-act per resource: exists and correct means skip; missing means create; wrong means fix to desired state.
How do I prove it?
Run twice on a fixture and compare outcomes. Same end state plus a clean second log is the proof.