Yeda AI Tips · #090

Español

Test Shell Scripts From a Path With Spaces

The cheapest shell bug detector? A folder name with a space in it. Unquoted variables look fine for months — right up until a path contains a space, the shell splits it into two arguments, and your script does something you never intended. You can buy that failure early, for free: run the script from a temp directory whose path has a space in it.

Why one space breaks so much

Bash scans the results of unquoted parameter expansion, command substitution, and arithmetic expansion for word splitting, using $IFS — by default space, tab, and newline. So rm $file on 01 - intro.mp3 becomes rm with three arguments, not one. ShellCheck's most famous warning, SC2086, exists precisely for this: unquoted expansions are first split on IFS, then each piece is expanded as a glob. Two silent transformations, both wrong for filenames.

The fix is one character pair — "$file" instead of $file — but the bug hides because developers test in ~/projects/myrepo, a path with zero spaces in it.

The 60-second harness

Make the failure environment the default test environment:

# 1. A temp dir with a space in its path — on purpose
dir="$(mktemp -d "${TMPDIR:-/tmp}/space test.XXXXXX")"

# 2. Run the script from there
cp myscript.sh "$dir/"
cd "$dir" && bash myscript.sh

# 3. Clean up
rm -rf "$dir"

mktemp -d creates the directory; the template just needs at least three consecutive Xs in the last component, and nothing stops you from putting a space before them. Every unquoted $dir, $PWD, $(dirname "$0"), or cd $target inside the script now fails loudly, right there — instead of quietly on a user's machine whose home folder is /Users/Ana Maria.

What to exercise once you're in there

Failure modeHow to trigger it
Word splitting / globbingThe spaced path itself — any unquoted expansion breaks
Current-directory assumptionsRun from the temp dir, not the repo root; relative paths that "just worked" stop working
Missing env varsenv -i bash myscript.sh — an empty environment exposes every $VAR you assumed was set
Failed subprocessesPoint the script at a command that exits non-zero; check it stops instead of continuing
Repeated runsRun it twice in the same dir — idempotence bugs (mkdir without -p, appends that double up) surface on run two

Lint first, then run

Static analysis catches the quoting class of bug before you execute anything. ShellCheck flags unquoted expansions, and the Google Shell Style Guide recommends it "for all scripts, large or small" — alongside its own quoting rule: always quote strings containing variables, command substitutions, spaces, or shell metacharacters. The order matters: lint catches what's statically visible; the spaced-path run catches the dynamic cases lint can't see (values that arrive at runtime from find, arguments, or config).

Power-user moves

Resources

Building an AI feature? Yeda AI designs, audits, and ships production LLM systems.

Talk to us · Read the blog