"Argument list too long": delete or move thousands of files on Linux
Fix "Argument list too long" for rm, mv, cp or grep with a wildcard: why the kernel refuses, and how find -delete, find -exec + and xargs handle any number of files.
by OhSudo ·
A folder filled up with files over months — temp files, cache entries, old logs — and the obvious cleanup fails:
$ rm *.tmp-bash: /usr/bin/rm: Argument list too longThe same happens with mv, cp, ls, grep, tar — any program you give a big wildcard. The program never even starts. Bash expands *.tmp into the full list of file names before running rm, and the kernel limits how much text a new program may receive as arguments: getconf ARG_MAX shows it, usually 2 MiB on Linux. Tens of thousands of file names are more than that.
So the fix isn’t a different rm option. It’s not putting all the names on one command line.
TL;DR
Or, to run any command on them in safe batches:
1. See how big the list is
600012220000echo works where rm doesn’t: it’s built into Bash, so the list never goes through the kernel. Here the names alone take about 2.2 MB — over the 2 MiB limit.
2. Delete with find
find walks the folder itself and deletes each file as it goes. There’s no list at all, so there’s no limit:
Check first what would be deleted — run it without -delete:
Useful extra conditions: -maxdepth 1 (don’t go into subfolders), -type f (only files), -mtime +7 (older than 7 days).
3. Any other command: find -exec + or xargs
For mv, cp, chmod, grep or anything else, let find (or xargs) split the list into batches that fit:
The + at the end makes find pass as many files as fit to each rm call, then start another one. (With \; instead, it would start one rm per file — correct, but much slower.)
xargs does the same with any list on its input. Use -print0 and -0, so file names with spaces or newlines can’t break it:
Moving files needs the destination before the list, so put it first with -t:
find . -name "*.tmp" -print0 | xargs -0 mv -t /var/archive/4. Other ways
- The whole folder: if everything in it can go,
rm -r /var/spool/app(one argument) works instead ofrm /var/spool/app/*. Recreate the folder if the app needs it. - Bash’s printf is a builtin, like
echo, so it can feed the list to xargs without hitting the limit:printf '%s\0' *.tmp | xargs -0 rm. - A loop works too, but starts one program per file — slow with 100,000 files:
for f in *.tmp; do rm -- "$f"; done. - tar reads the list from its input:
find . -name "*.log" -print0 | tar --null -czf logs.tar.gz -T -.
Note
Fix the cause, too. A folder with this many files usually means a cleanup that never runs: a missing cron job (see Cron job not running) or an app that never deletes its temp files. A daily find /var/spool/app -name "*.tmp" -mtime +1 -delete keeps it from coming back.
Shell, we have a problem!
Similar, but different: No space left on device with plenty of free space can mean the filesystem ran out of inodes — millions of tiny files; see No space left on device. Too many open files is about files a program has open, not their number in a folder — see Too many open files. For more recipes, see the find, grep, sed and awk Cheat Sheet. To learn find step by step, try that lesson.
$ ./practice.sh
Practice this in the terminal
Open the Terminal Playground with this article’s scenario loaded. It is safe and runs in your browser.
Found this useful? Share it.
Found a mistake? Let us know at contact@ohsudo.com.