Bash Loop Runs Once With No Matching Files: Choose Nullglob or an Error
By ON Lab · Sources checked November 8, 2026
With Bash’s default filename expansion, an unmatched pattern such as ./*.csv stays as a literal word. A for loop can therefore run once even when no CSV files exist. Choose whether no match should mean zero work or an error, then use nullglob or failglob within a deliberate option scope.
Reproduce the literal iteration
Run this in a disposable empty directory under Bash:
for file in ./*.csv; do
printf '<%s>\n' "$file"
doneOur Bash 3.2.57 fixture printed <./*.csv> once. It did not discover a hidden real file. Filename expansion had left the unmatched word intact, and the loop processed that word.
This matters before adding a copy, conversion or rename command to the body. A successful loop invocation is not proof that any intended input existed. First keep the body as printf and inspect the selected names.
Make no match mean zero work
(
shopt -s nullglob
files=(./*.csv)
printf 'count=%s\n' "${#files[@]}"
for file in "${files[@]}"; do
printf '<%s>\n' "$file"
done
)In the empty fixture this printed count=0 and no file rows. In a second fixture containing a b.csv and c.csv, it printed count=2 and preserved the space-containing filename as one value. The array expansion is quoted to preserve each matched pathname as its own argument.
The parentheses deliberately limit the shell-option change to a subshell. The example does not export a result array to the outer shell. If later code needs that array, design and test the option’s save/restore scope in the current shell rather than assuming subshell assignments persist.
Or make no match a failure
shopt -s failglob
for file in ./*.csv; do
printf '<%s>\n' "$file"
doneOur empty-directory case produced an expansion error and a nonzero shell result; the loop body did not run. That can fit a workflow in which having no inputs is exceptional. Do not convert the error to success unless the surrounding contract explicitly permits an empty input set.
Quoting the pattern is a different operation
for file in "./*.csv"; do
printf '<%s>\n' "$file"
doneThis printed the literal pattern in both our empty and nonempty fixtures. Quoting the entire wildcard expression prevents its pathname expansion. That is different from quoting each resulting value inside the loop. A pattern passed to another program’s own matching option may need quoting; a shell-expanded input list has a different boundary.
Decide what kind of match is usable
A name ending in .csv can be a directory, a link or an ordinary file. Filename expansion selects names; it does not validate their contents or certify that they remain readable. If the operation accepts regular-file targets only, add the appropriate type and error checks after reviewing how links should be treated.
Matching also depends on the current directory and the shell’s other options. Use an explicit reviewed input directory. These examples do not enable recursive globbing, include dot-prefixed names or run under POSIX sh. They were tested with Bash and do not rely on parsing ls output.
Keep filename framing separate
The NUL-delimited filename guide explains another way to carry arbitrary names between programs. The Python glob guide addresses a different API and hidden-component policy. Neither changes Bash’s unmatched-pattern rule.
- Test an empty input directory.
- Test ordinary names and one containing a space.
- Choose empty success or explicit failure.
- Inspect exact matches before adding writes.
- Test under the actual Bash version and option set, including any nounset policy in the surrounding script.
The official manual and original public answers are free alternatives. This guide adds an eight-case matrix separating default expansion, nullglob, failglob and a fully quoted pattern.
Method: current GNU Bash documentation, a historical public file-mask question and two synthetic directories tested with Bash 3.2.57/macOS. No actual batch conversion, deletion, recursive discovery, other shell or arbitrary surrounding option combination was tested.