Usually found in the middle of another emergency
A directory with hundreds of thousands of files is typically also the reason the filesystem is out of inodes. If No space left on device brought you here, see No Space Left on Device With Free Space first. For age-based cleanup of a log directory, see Delete Old Log Files.
You found the directory full of files and typed the obvious rm *.log. Bash answered Argument list too long and deleted nothing. The same happens to ls *.log, cp *.log, mv *.log, and to a script that has worked for months until the directory it cleans crossed an invisible size. The glob is not the problem. The shell expanded it happily. The kernel refused to start rm with that many bytes of arguments, and it failed before rm removed anything.
What Does the Error Look Like?
Reproduced here on 2026-09-28 (Kali, bash 5.3.9, GNU findutils 4.11.0) in a scratch directory with 200,000 empty files named job-000001.log to job-200000.log:
Exit 126, "cannot execute", and all 200,000 files still there. ls with the same glob fails the same way:
The glob itself expands fine. The builtin echo receives all of it, because a builtin never goes through the kernel's exec:
4,200,000 bytes of names, twice the 2,097,152-byte ARG_MAX, before counting the pointer the kernel stores for each argument. xargs reports the real budget after the environment takes its share:
How Do I Fix Argument List Too Long?
Stop handing the list to one program. Three ways, from simplest to most general:
The third form was run here on a copy of the 200,000 files:
-maxdepth 1 keeps find to the one directory, matching what the glob would have matched. \0 separators with -0 keep names with spaces or newlines intact. The -- stops a file named -rf being read as an option. And {} + rather than {} \; is the difference between a handful of mv processes and 200,000 of them.
The Script
Save as bulk-delete-files.sh. It counts matches without ever building an argument list, dry-runs by default, and deletes with find -delete on --apply.
Quote the pattern when you call it ('*.log'), so the shell passes it to find instead of expanding it and failing on the way in.
What Does the Script Print?
On the 200,000-file directory:
Two hundred thousand files in under a second. The last run exits 1 on purpose: from cron, a pattern that suddenly matches nothing is more often a wrong path than a clean directory, and it should say so.
How Do I Schedule It?
Nightly, for a spool directory that a job fills and nothing empties:
For age-based retention (keep the newest N, delete the rest after D days) use Log Retention Cleanup instead; this script deletes everything that matches. The find command builder builds the find line for other patterns and actions. Cleanup jobs that run unattended need a lock and a log line proving they ran, which The Production Bash Toolkit packages as bashlib.sh and a cleanup.sh.
Frequently Asked Questions
What is the maximum number of arguments in Linux?
There is no fixed count. The limit is in bytes: ARG_MAX, which getconf ARG_MAX reports (2097152 on current Linux, one quarter of the default 8 MB stack). It covers every argument string, its terminating null byte, a pointer per argument, and the whole environment. Short file names fit more; long paths fit fewer. xargs --show-limits prints the usable figure after the environment is subtracted.
Why does echo *.log work but rm *.log fail?
echo and printf are bash builtins. They run inside the shell and never call exec, so ARG_MAX never applies to them. rm, ls, cp and mv are separate programs, and the kernel refuses to exec any program whose argument list is larger than ARG_MAX. That is why printf '%s\0' *.log | xargs -0 rm works: the builtin prints the names and xargs splits them into batches that fit.
Is find -delete faster than xargs rm?
Usually, and it is simpler. find -delete unlinks each file itself as it walks the directory, with no second process and no batching. xargs rm runs rm once per batch, which is still far better than -exec rm {} \; (one rm per file). On this page's test, find -delete removed 200,000 files in 0.67 seconds.
How do I move a very large number of files without Argument list too long?
Use find with -exec and mv's -t option so the target comes first: find src -maxdepth 1 -name '*.log' -exec mv -t /dest {} +. The + packs as many names into each mv as fit under ARG_MAX, and -t lets them come last. For cp use cp -t the same way.
Can I increase ARG_MAX?
Only a little. On Linux, ARG_MAX is one quarter of the stack size limit, but the kernel caps it at 6 MB. Here, ulimit -s 65536 raised getconf ARG_MAX from 2097152 to 6291456, not to 16 MB. That moves the ceiling without removing it; a directory that keeps growing fails again later. Changing the command to find or xargs removes the problem for any number of files.
Part of the bash snippets collection
Related Scripts
- Delete Old Log Files —
find -mtime +N -deletefor age-based cleanup - Log Retention Cleanup — keep the newest N, delete the rest past D days
- No Space Left on Device With Free Space — when the file count itself is what filled the disk
- Find Duplicate Files —
findwith-print0on a large tree