Bash Error Guide: 'ambiguous redirect' — Fix Redirect Target Expansion
Fix 'ambiguous redirect' in Bash: quote redirect targets, handle empty or unset variables and word-splitting, and create missing directories to resolve it.
- #bash
- #automation
- #troubleshooting
- #errors
Stuck on this Bash & Python Automation error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
Bash prints ambiguous redirect when the target of a redirection (>, >>, <, 2>) does not resolve to exactly one filename. The most frequent cause is a variable that expanded to nothing or to multiple words:
./run.sh: line 8: $LOGFILE: ambiguous redirect
Bash is refusing to guess. A redirect must name one target; if the word after > expands to zero words (empty variable) or more than one word (unquoted value with spaces), Bash cannot decide which file you meant and aborts the command rather than truncating the wrong file.
Symptoms
- A redirection like
command > "$OUT"fails withambiguous redirectwhile the command itself is fine. - The script works for some inputs (single-word paths) and fails for others (paths with spaces, or empty variables).
- Output that should have gone to a file never appears, and the command’s real work didn’t run.
- The error references a variable name (
$LOGFILE,$OUT) that turns out to be empty or unset. - A redirect to a path in a directory that doesn’t exist yet fails — sometimes as
ambiguous redirect, sometimes asNo such file or directory.
Common Root Causes
- Empty or unset variable as the target —
> $LOGwhere$LOGis unset expands to>with no filename. - Unquoted target containing whitespace —
> $OUTwhereOUT="/var/log/my app.log"word-splits into two targets. - Unquoted target with glob characters — a
*,?, or[in the path expands to zero or multiple matches. - Command substitution yielding empty or multi-line output —
> $(date +%F)is fine, but> $(some-cmd)that prints nothing or several lines breaks. - Missing parent directory — the directory in the target path does not exist; depending on context this surfaces as ambiguous redirect or
No such file or directory. - Wrong file-descriptor syntax —
>&$FDwith an emptyFD, or a space in a fd-dup like2 >&1, confuses the redirect parser. noclobberinteractions — withset -o noclobber, redirecting to an existing file needs>|, and mistakes there can compound with expansion issues.
Diagnostic Workflow
Print the exact target the shell is about to use, with quoting made visible:
printf 'target=[%s] words=%d\n' "$LOGFILE" $(set -- $LOGFILE; echo $#)
If words is 0, the variable is empty/unset; if it’s 2 or more, unquoted word-splitting is the problem. Turn unset variables into a hard error so the real cause surfaces earlier and clearer:
set -u # referencing $LOGFILE while unset now aborts with 'unbound variable'
Trace the line and see the expansion:
bash -x ./run.sh 2>&1 | grep -n -i 'ambiguous\|+ .*>'
Confirm the parent directory exists and is writable:
dir=$(dirname -- "$LOGFILE")
[ -d "$dir" ] && [ -w "$dir" ] && echo "ok: $dir" || echo "missing/unwritable: $dir"
Check whether the value contains spaces or glob characters:
printf '%q\n' "$LOGFILE" # %q escapes spaces and specials, revealing them plainly
Example Root Cause Analysis
A backup script wrote its log to a per-run file:
LOGDIR=/var/log/backups
LOGFILE=$LOGDIR/backup-$RUN_ID.log
echo "starting backup" > $LOGFILE
It failed on some hosts with:
backup.sh: line 6: $LOGFILE: ambiguous redirect
Running with bash -x exposed the expansion:
+ RUN_ID=
+ LOGFILE=/var/log/backups/backup-.log
+ echo 'starting backup'
backup.sh: line 6: $LOGFILE: ambiguous redirect
$LOGFILE was not empty — so why ambiguous? The real trigger was two combined issues on the failing hosts: the redirect target was unquoted, and on those hosts LOGDIR was set from an environment variable that contained a trailing space and a glob (/var/log/backups /tmp/*) due to a misconfigured deploy. Unquoted, $LOGFILE word-split into multiple targets. The robust fix is to always quote the target and validate the path first:
#!/usr/bin/env bash
set -euo pipefail
LOGDIR=/var/log/backups
RUN_ID=${RUN_ID:?RUN_ID must be set}
LOGFILE="$LOGDIR/backup-$RUN_ID.log"
mkdir -p -- "$LOGDIR" # ensure the directory exists
echo "starting backup" > "$LOGFILE" # quoted: exactly one target, spaces and globs safe
Quoting "$LOGFILE" guarantees a single-word target regardless of spaces or glob characters, ${RUN_ID:?...} refuses to run with an empty run id, and mkdir -p removes the missing-directory failure mode.
Prevention Best Practices
- Always quote redirect targets —
> "$OUT", never> $OUT; this single habit prevents the empty, whitespace, and glob variants at once. - Validate the variable before redirecting —
${OUT:?output path is required}fails fast with a clear message instead of an obscure ambiguous redirect. - Create parent directories —
mkdir -p -- "$(dirname -- "$OUT")"before redirecting so a missing directory can’t break the write. - Enable strict mode —
set -euo pipefail; withset -u, an unset target variable produces a preciseunbound variableerror naming the culprit. - Use
--and quoting for paths from data — protects against paths that start with-or contain spaces and specials. - Guard command-substitution targets — assign
$(...)output to a variable, verify it’s non-empty and single-line, then redirect to the quoted variable. - Run ShellCheck — it flags unquoted redirect targets (SC2086) directly.
Quick Command Reference
echo x > "$OUT" # always quote the target
: "${OUT:?output path required}" # fail fast if empty/unset
mkdir -p -- "$(dirname -- "$OUT")" # ensure parent directory exists
printf '%q\n' "$OUT" # reveal spaces/globs in the value
bash -x ./script.sh # trace the expansion of the target
set -u # make unset variables fatal and named
[ -d "$(dirname "$OUT")" ] && echo ok # confirm parent dir exists
Conclusion
ambiguous redirect is Bash refusing to redirect because the target word did not resolve to exactly one filename — usually an empty/unset variable or an unquoted value that word-split on spaces or globs. The cure is almost always the same one line: quote the target (> "$OUT"). Back that up with set -u to catch unset variables by name, ${OUT:?...} to fail fast, and mkdir -p to guarantee the destination directory exists. Quote every redirect target and this error effectively disappears from your scripts.
Fixed it? Get 500 Bash & Python Automation & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.