Bash error: Argument list too long

When a glob expands to more files than ARG_MAX, Bash fails with "Argument list too long". Use `find -exec`, xargs, or batched globs.

Error String

bash: /bin/rm: Argument list too long

Tldr

The kernel limits the total bytes of arguments + environment for a process (typically ~2 MB). A glob that expands to tens of thousands of files exceeds it. Use `find ... -delete`, `find ... -exec ... +`, or `xargs` to batch.

Cause

Commands like `rm *.log`, `mv * /backup/`, or `grep pattern *.txt` materialize every match into a single argv. When the directory holds thousands of files, the total argv size exceeds ARG_MAX (`getconf ARG_MAX`).

Repro

# In a dir with 100k log files:
rm *.log                       # /bin/rm: Argument list too long

Fix

# find handles batching internally:
find . -maxdepth 1 -name '*.log' -delete

# Or pipe through xargs (one exec per batch):
find . -maxdepth 1 -name '*.log' -print0 | xargs -0 rm

# Or a shell loop (slowest but always works):
for f in *.log; do rm -- "$f"; done

Explanation

The for-loop form works because `*.log` is expanded by the shell into the loop, which only consumes a few entries at a time — argv is never built. It is slower than `find -delete` but never overflows.

Related Shellcheck

SC2035

Faq

Q

Why does the same command work in another directory?

A

The limit depends on how many files the glob matches and how big the environment is, so it appears only past a threshold.

Q

Is xargs safe with unusual filenames?

A

Only with `-0` and a `find -print0` producer; plain `xargs` splits on whitespace and quotes.

Deep Dive

Heading

A kernel limit, not a shell bug

Body

E2BIG is raised by `execve` when the combined size of arguments and environment exceeds the system limit — check it with `getconf ARG_MAX`. A glob such as `rm *.log` in a directory with a hundred thousand files expands before the command runs, so the shell hands the kernel a single enormous argument list. The environment counts towards the same budget, which is why the failure appears in CI (with large exported variables) before it appears locally.

Heading

Batch the work instead

Body

`find . -maxdepth 1 -name "*.log" -print0 | xargs -0 rm --` splits the work into as many `rm` invocations as needed and handles spaces and newlines in filenames safely. `find ... -delete` avoids exec entirely for deletion, and `find ... -exec cmd {} +` batches arguments the same way `xargs` does. For copies and moves, `rsync` streams the file list rather than passing it as arguments. A `while IFS= read -r -d ""` loop is the last resort when each item needs shell logic.

Checklist

Check the ceiling with `getconf ARG_MAX`.

Replace bare globs with `find ... -print0 | xargs -0`.

Use `find -delete` or `-exec cmd {} +` where they apply.

Trim large exported environment variables in CI.