This backup script silently archives the wrong paths — how do you debug and fix it?
A backup script is supposed to archive three directories into one tarball, but the resulting archive contains the wrong paths and the script still prints backup done.
Constraints: the directory list is fixed and one directory name contains a space. Explain how you would locate the fault (tracing / static analysis) and give the fix.
#!/usr/bin/env bash
# Archive a list of directories into one tarball.
paths="/var/log /srv/My App /etc"
tar -czf backup.tgz $paths
echo "backup done"
Find and fix the bug.
Run it with bash -x script (or add set -x) and you see tar expanding to /srv/My and App as separate arguments — the unquoted $paths word-splits on every space. shellcheck flags it as SC2086. The fix is to store the paths in an array and pass "${paths[@]}", which keeps each path as one argument.
- ✗Assuming multiple paths fit safely in one space-separated scalar variable
- ✗Not running
bash -xorshellcheck, so the silent word-split goes unseen - ✗Leaving
$pathsunquoted, soMy Appsplits into two arguments
- →What does
shellcheckcode SC2086 warn about, and how do you silence it correctly? - →Why does
set -xreveal a word-splitting bug that reading the source does not?
Solution
The script keeps several paths in one space-separated scalar and then passes it to tar unquoted. The unquoted $paths undergoes word-splitting, so /srv/My App breaks into two arguments — /srv/My and App. The script still prints backup done because tar succeeds (it archives the wrong-but-existing paths) and nobody checks the exit code.
Debugging:
bash -x ./backup.sh # trace: shows tar ... /srv/My App as separate arguments
shellcheck ./backup.sh # SC2086: Double quote to prevent globbing and word splitting
The fix is to store the paths in an array and pass it quoted:
#!/usr/bin/env bash
set -euo pipefail
paths=(/var/log "/srv/My App" /etc)
tar -czf backup.tgz "${paths[@]}"
echo "backup done"
The array holds each path as its own element, and "${paths[@]}" expands to exactly as many arguments as there are elements, preserving spaces. set -euo pipefail turns future failures from silent into loud.