Updated: 10 October 2026 · Applies to: GNU rm 9.5 (AlmaLinux 10) and 9.7 (Debian 13, Ubuntu 26.04), GNU find 4.10.0, bash 5.2 and 5.3; the same commands work on Ubuntu 24.04, Rocky Linux and RHEL
To remove all files with one extension in the current folder, run rm *.log. To remove them from all subfolders as well (recursively), use find . -type f -name '*.log' -delete. To empty a folder completely, hidden files included, run find /path/to/folder -mindepth 1 -delete, and to delete a folder together with everything in it, run rm -r folder (rmdir only removes empty folders).
rm *.log find . -type f -name '*.log' -delete find /path/to/folder -mindepth 1 -delete rm -r folder
Linux has no recycle bin on the command line: deleted files are gone. Preview first. Run the find command without -delete, or replace rm with ls, and check the list before you delete anything.
The examples use this test folder on Debian 13 (Ubuntu 26.04 and AlmaLinux 10 gave the same results):
.env app.log error.log keep.zip notes.txt photo.JPG report.odt cache/a.log cache/b.tmp cache/old/c.log
1. Remove all files with an extension in one folder
$ rm -v *.log removed 'app.log' removed 'error.log'
-v lists each file as it is removed. Only the current folder is affected: cache/a.log stays. Some notes:
- Several extensions:
rm -v *.log *.tmp. If one pattern matches nothing,rmreportscannot remove '*.tmp': No such file or directoryand still removes the rest. - Patterns are case-sensitive:
*.jpgdoes not matchphoto.JPG. - Another folder:
rm /var/www/uploads/*.tmp.
2. Delete files by extension recursively
- List what will be deleted:
$ find . -type f -name '*.log' ./cache/old/c.log ./cache/a.log ./app.log ./error.log
- Delete the same files by adding
-deleteat the end:find . -type f -name '*.log' -delete
Keep the quotes around '*.log', so that find receives the pattern instead of the shell expanding it. Useful variations:
- See each file as it goes:
find . -type f -name '*.log' -exec rm -v {} + - Several extensions:
find . -type f \( -name '*.log' -o -name '*.tmp' \) -print -delete - Any case (
.jpg,.JPG): use-iname '*.jpg'. - Only files older than 30 days: add
-mtime +30before-delete.
"Argument list too long": with very many files, rm *.tmp fails before rm even starts. In our test with 150,000 files, bash stopped with /usr/bin/rm: Argument list too long (the limit, getconf ARG_MAX, was 2,097,152 bytes). find . -maxdepth 1 -name '*.tmp' -delete removed all of them in about 7 seconds, because find does not pass the names on a command line.
3. Remove all files in a directory
rm folder/* removes the files but stops at subfolders, and * never matches hidden names such as .env or .htaccess:
$ rm -v /srv/demo/* removed '/srv/demo/app.log' rm: cannot remove '/srv/demo/cache': Is a directory removed '/srv/demo/error.log' ... $ ls -A /srv/demo .env cache
(output shortened) Choose the command that matches what you want to keep:
- Everything inside, keep the folder itself:
find /srv/demo -mindepth 1 -delete. This also removes hidden files and subfolders; afterwardsls -A /srv/demoprinted nothing and the empty folder was still there. - Everything except hidden files:
rm -rv /srv/demo/*(it left.envin our test). - Only the files, not the subfolders:
find /srv/demo -maxdepth 1 -type f -delete - With rm, hidden files included:
shopt -s dotglobfirst (bash), thenrm -rv /srv/demo/*, thenshopt -u dotglob.
4. rmdir and all contents: delete a folder and everything in it
$ rmdir demo rmdir: failed to remove 'demo': Directory not empty $ rm demo rm: cannot remove 'demo': Is a directory
rmdir and rm -d remove empty folders only. For a folder with contents, use rm -r (recursive). It asks before each write-protected file; rm -rf never asks, so check the path twice. A safer middle way is rm -rI demo, which asks once before it starts (rm: remove 1 argument recursively?). What each flag does is explained in what rm -rf does, and deleting folders by name across a whole tree in search and remove directories recursively.
5. Delete all files except one or a few
With find (works in any shell). Preview with -print only, then add -delete:
$ find . -maxdepth 1 -type f ! -name '*.zip' -print -delete ./notes.txt ./photo.JPG ./app.log ./report.odt ./error.log ./.env
Everything except keep.zip went, including the hidden .env. To keep several patterns, group them: find . -type f ! \( -name '*.zip' -o -name '*.odt' \) -delete. Without -maxdepth 1, this also deletes files in subfolders.
With bash extended globbing:
shopt -s extglob rm -v !(keep.zip|report.odt) shopt -u extglob
This keeps the two names, skips subfolders (rm: cannot remove 'cache': Is a directory) and leaves hidden files alone. In a script, shopt -s extglob must be on its own line before the line that uses !( ); on the same line, bash fails with syntax error near unexpected token `('.
With GLOBIGNORE: GLOBIGNORE='*.zip:*.odt'; rm -v *; unset GLOBIGNORE keeps the matching files, but be careful: setting GLOBIGNORE makes * match hidden files too. In our test it removed .env.
6. Avoid the common accidents
- Put
-deletelast.findworks left to right, sofind . -delete -name '*.log'deletes every file and folder below the current one. We tried it: the test folder was empty afterwards. - Guard variables in scripts. If
$DIRis empty,rm -rf "$DIR"/*becomesrm -rf /*. Writerm -rf "${DIR:?}"/*: bash then stops withDIR: parameter null or not setinstead. rm -rf /itself is refused by default (rm: it is dangerous to operate recursively on '/'), but/*is not protected.- Patterns with
*behave differently infind,lsandrm; see how to use wildcards safely.
If something important was deleted by mistake, stop writing to that disk and follow how to recover a deleted file in Linux. A recent backup is the only reliable way back.
Ucartz services for this topic
- KVM VPS hosting: NVMe SSD and full root access, with Free Basic Managed Support.
- Unmanaged dedicated servers: full root access and free IPMI KVM, with Free Basic Managed Support.
- Linux server management: hardening, patching, monitoring and automation for Ubuntu, Debian, RHEL and AlmaLinux.
