The “find + xargs” combo is a classic for cleaning up old logs, but it can be a double‑edged sword if you’re not careful.
Below is a step‑by‑step guide that shows how to target only the log files you want to delete, keep your home folder safe, and understand the trade‑offs of the different options you’ll see.
Why find and xargs instead of rm -r?
find is the Swiss‑army knife of file searching: you can filter by name, age, size, permissions, and more.
xargs takes the list that find spits out and feeds it to another command, usually rm.
The pair is efficient because it processes files in batches, sidestepping the “argument list too long” error that can bite you if you try to delete thousands of files with a single rm.
1. Identify the log files you actually want to delete
Before you start deleting, run a dry‑run to see what will be affected.
Assume your logs live under /var/log and you want to delete files older than 30 days that end in .log.
find /var/log -type f -name '*.log' -mtime +30 -print
-type f– only regular files-name '*.log'– match the pattern-mtime +30– modified more than 30 days ago-print– show the full path
If the output looks correct, you’re ready to delete.
2. Safely delete with xargs
The most common pattern is:
find /var/log -type f -name '*.log' -mtime +30 -print0 | xargs -0 rm -f
What each part does
| Component | Purpose |
|---|---|
-print0 |
Outputs filenames followed by a null byte, which handles spaces and newlines in filenames. |
xargs -0 |
Reads null‑terminated strings, matching -print0. |
rm -f |
Force delete without prompting. |
Why -print0 / -0?
Log files rarely contain spaces, but if you ever have a custom log name like app log 2024-11-01.log, the null‑byte approach prevents mis‑parsing.
3. Avoid touching your home directory
A common mistake is to run find / -type f -mtime +30 -name '*.log' -print0 | xargs -0 rm -f from the root.
That will delete every log file on the system, including those in /home/youruser, which might be application logs you actually need.
Two safeguards
-
Explicit path – always specify the directory you want to clean, e.g.,
/var/log.
Avoidfind /unless you’re absolutely sure. -
Use
-pathto exclude – if you must search the whole tree, exclude/home:find / -type f -name '*.log' -mtime +30 \ ! -path '/home/*' -print0 | xargs -0 rm -fThe
! -path '/home/*'clause tellsfindto skip everything under/home.
4. Test with -exec before xargs
find can run a command directly on each file.
This is safer for a first run because you can see the exact command that will execute.
find /var/log -type f -name '*.log' -mtime +30 -exec rm -i {} \;
-exec rm -i {} \;– prompts before each delete.- If you’re comfortable, replace
-iwith-fto skip prompts.
5. Batch size matters
When you have thousands of files, xargs will by default group them into batches of 256 or so.
You can control the batch size with -n:
find /var/log -type f -name '*.log' -mtime +30 -print0 | xargs -0 -n 100 rm -f
-n 100– pass at most 100 filenames tormat a time.
Smaller batches reduce the risk of hitting the maximum argument length, but increase the number ofrminvocations.
6. Using -delete instead of xargs
Modern find supports the -delete action, which removes files directly:
find /var/log -type f -name '*.log' -mtime +30 -delete
Pros:
- No need for
xargs. - Simpler syntax.
Cons:
-deletestops processing the current directory if it fails (e.g., due to permissions).- Some older
findversions (e.g., on very old Debian releases) may not support-delete.
If you’re on a recent distribution (Debian 12, Ubuntu 24.04, Fedora 40, etc.), -delete is usually the cleanest choice.
7. Logging the deletion
It’s a good practice to keep a record of what you delete, especially on a production server.
find /var/log -type f -name '*.log' -mtime +30 -print0 | \
tee /tmp/old_logs_to_remove.txt | \
xargs -0 -r rm -f
teewrites the list to/tmp/old_logs_to_remove.txtwhile passing it through toxargs.-r(or--no-run-if-empty) preventsxargsfrom runningrmif the list is empty.
8. Common pitfalls and how to avoid them
| Pitfall | Symptom | Fix |
|---|---|---|
Accidentally deleting /home logs |
rm: cannot remove '/home/...': Permission denied or files vanish |
Use explicit path or ! -path '/home/*' |
| Files with spaces or newlines | rm: cannot remove 'app log 2024-11-01.log': No such file or directory |
Use -print0 / -0 |
| Running as root without checks | System crash or data loss | Test with -print or -exec rm -i first |
xargs ignoring empty input |
rm: missing operand |
Add -r or --no-run-if-empty |
| Over‑aggressive age filter | Deleting recent logs | Verify -mtime +30 vs -mtime -30 |
9. Automating with a cron job
If you routinely clean logs, schedule a daily job:
# /etc/cron.d/clean-logs
15 2 * * * root find /var/log -type f -name '*.log' -mtime +30 -delete
- Runs at 02:15 every day.
rootensures it has permission to delete system logs.- The
-deleteaction is safe and concise.
Always test the cron command manually before adding it to the crontab.
10. Security considerations
-
Least privilege – run the deletion as a user that only has access to the target directory.
For/var/log, therootuser is typical, but if you’re cleaning user‑specific logs, use that user’s account. -
Audit trail – keep a log of deletions (see section 7).
On a multi‑user system, this helps trace accidental or malicious deletions. -
Avoid
sudo rm -rf /– a typo can wipe the whole system.
Usesudo -lto review allowed commands and considersudo -vbefore running the script.
11. When xargs is not enough
If you need more complex filtering (e.g., delete logs only from a specific service), combine find with grep:
find /var/log -type f -name '*.log' -mtime +30 -print0 | \
xargs -0 -I{} sh -c 'basename "{}" | grep -q "^nginx" && rm -f "{}"'
This deletes only files whose base name starts with nginx.
The -I{} placeholder lets you run a shell command per file.
12. Quick reference cheat sheet
| Command | What it does |
|---|---|
find /var/log -type f -name '*.log' -mtime +30 -print |
List old logs |
find /var/log -type f -name '*.log' -mtime +30 -delete |
Delete them (no xargs) |
| `find /var/log -type f -name ‘*.log’ -mtime +30 -print0 | xargs -0 rm -f` |
| `find /var/log -type f -name ‘*.log’ -mtime +30 -print0 | tee /tmp/old_logs.txt |
| `find / -type f -name ‘.log’ -mtime +30 ! -path ‘/home/’ -print0 | xargs -0 rm -f` |
13. Resources
- GNU find manual –
-delete - Linux man page for
xargs - Debian Wiki – Log Rotation – for complementary log‑rotation strategies
See also
- How to Keep Your Podman “Hello‑World” Container from Filling Disk With Logs
- How to set up a local Nginx reverse proxy for home‑hosted services without exposing ports to the internet
- Turning a Raspberry Pi into a DIY Caddy Reverse Proxy for Home‑Hosted Services
- Why My Custom Systemd Timer Keeps Firing Twice and How to Fix It
- Using find + xargs to purge old log files without risking accidental deletes