Using find + xargs to purge old log files without risking accidental deletes

Safely Removing Old Log Files with find and xargs

Log files are the lifeblood of debugging, but they’re also the biggest culprits when a disk starts to feel cramped. If you’re running a home server, a small NAS, or just a personal laptop, you’ll often need a quick way to prune logs older than a set age without accidentally wiping something vital. The classic find … | xargs combo is a battle‑tested, script‑friendly solution that works on almost every Linux box.

Below is a step‑by‑step walk‑through that shows how to:

  1. Locate the files you want to delete.
  2. Double‑check the list before you hit delete.
  3. Delete with safeguards against accidental mass removal.
  4. Automate the routine with a cron job.
  5. Deal with edge cases like long names or spaces.

The examples use the GNU coreutils version of find and xargs—the ones that ship on most distros. If you’re on BSD or another variant, the syntax may shift a bit, but the overall pattern stays the same.


Why find + xargs is a Good Fit

  • Speed: find scans once; xargs batches the delete calls, cutting down on rm invocations.
  • Safety: Pipe the output through less or cat to review before you delete.
  • Flexibility: Combine size, age, name, and more in one line.
  • Portability: Both tools are POSIX‑standard and present on virtually all Unix‑like systems.

1. Locating Old Log Files

Let’s say you want to delete every .log file in /var/log that’s older than 30 days.

find /var/log -type f -name '*.log' -mtime +30
  • -type f keeps the search to regular files.
  • -name '*.log' matches the pattern.
  • -mtime +30 grabs files modified more than 30 days ago.

Run it alone first—it just lists the candidates. That’s your sanity check.

Handling Spaces and Special Characters

If a filename contains spaces, newlines, or other oddities, the default find output can break the pipeline. Use -print0 to emit a null‑terminated list, and pair it with xargs -0:

find /var/log -type f -name '*.log' -mtime +30 -print0 | xargs -0 ls -l

The -print0/-0 dance guarantees every filename is parsed correctly, no matter what characters it holds.


2. Verifying Before Deletion

A common rookie mistake is to pipe straight into rm. Instead, first pipe into less or cat:

find /var/log -type f -name '*.log' -mtime +30 -print0 | xargs -0 -n 1 -I {} echo {}

The echo step shows each path. If everything looks right, replace echo with rm -i to prompt for each deletion:

find /var/log -type f -name '*.log' -mtime +30 -print0 | xargs -0 -i rm -i {}

rm -i forces an interactive prompt. If you’re comfortable with the list, skip the prompt with rm -f.


3. The Production‑Ready Delete Command

Once you’ve verified the list, run the actual delete. The safest form uses xargs -r (run only if there’s input) and -0 for null separation:

find /var/log -type f -name '*.log' -mtime +30 -print0 | xargs -r -0 rm -f
  • Why -r?
    If find returns nothing, xargs would otherwise invoke rm with no arguments, which could delete the current directory or do nothing. -r prevents that.

  • Why -f?
    -f forces deletion without prompting. You’ve already checked the list, so it’s safe.


4. Automating with Cron

Most homelab owners want this to run automatically. Create a script, e.g., /usr/local/bin/clean_logs.sh:

#!/usr/bin/env bash
# clean_logs.sh
# Delete /var/log/*.log files older than 30 days

LOG_DIR="/var/log"
AGE_DAYS=30

find "$LOG_DIR" -type f -name '*.log' -mtime +$AGE_DAYS -print0 | \
    xargs -r -0 rm -f

Make it executable:

chmod +x /usr/local/bin/clean_logs.sh

Add a cron job that runs once a week:

0 2 * * 0 /usr/local/bin/clean_logs.sh

This schedules the script to run at 02:00 on Sundays. Adjust the timing to match your disk‑usage patterns.


5. Advanced Filters

5.1 Size‑Based Deletion

Sometimes you want to target logs that are both old and large. Combine -size with -mtime:

find /var/log -type f -name '*.log' -mtime +30 -size +10M -print0 | \
    xargs -r -0 rm -f

This removes files older than 30 days that exceed 10 MiB.

5.2 Excluding Certain Subdirectories

If you need to keep logs from a particular service, use -not -path:

find /var/log -type f -name '*.log' -mtime +30 \
    -not -path '/var/log/nginx/*' -print0 | \
    xargs -r -0 rm -f

This skips anything under /var/log/nginx.

5.3 Using -exec Instead of xargs

find’s -exec can run a command on each file individually. It’s slower but avoids xargs altogether:

find /var/log -type f -name '*.log' -mtime +30 -exec rm -f {} +

The trailing + tells find to pass as many arguments as possible to a single rm call, similar to xargs.


6. Handling Very Long Filenames

On systems where filenames can exceed the shell’s argument limit, xargs will automatically split the list into smaller batches. The -n option can enforce a maximum number of arguments per invocation:

find /var/log -type f -name '*.log' -mtime +30 -print0 | \
    xargs -r -0 -n 100 rm -f

This forces rm to run with at most 100 filenames per call.


7. Logging the Deletion

For audit purposes, it’s handy to record what got deleted. Append the list to a log file before deletion:

find /var/log -type f -name '*.log' -mtime +30 -print0 | \
    tee /var/log/clean_logs_$(date +%Y%m%d).log | \
    xargs -r -0 rm -f

tee writes the list to a file and passes it through to xargs. The log file name includes the date for easy reference.


8. Common Pitfalls and How to Avoid Them

Pitfall What Happens Fix
Accidentally deleting /var/log itself rm -f /var/log removes the directory Use -type f to restrict to files.
Running rm without -f on an empty list rm prompts for confirmation Use xargs -r to skip if no input.
Forgetting -print0/-0 with filenames containing spaces Some files are missed or mis‑parsed Always use null separation for safety.
Deleting logs that are still in use by a service Service may crash or lose data Exclude active directories or stop services first.
Running the script as root without logging Loss of traceability Log the deletion list or use auditd.

9. Security Considerations

Running the command as root gives it the power to delete anything. Keep the script in a secure location (/usr/local/bin) and set the right permissions:

chmod 755 /usr/local/bin/clean_logs.sh

If you’re using cron, make sure the crontab entry is owned by the root user and not writable by others. Avoid using sudo in the script; instead, run the cron job as root.


10. Alternatives Worth Knowing

  • logrotate: For many services, logrotate already handles rotation and deletion. Configure it to keep a certain number of archives or a maximum size.
  • systemd‑journald: If you use journald, set SystemMaxUse= in /etc/systemd/journald.conf to cap disk usage automatically.
  • trash-cli: If you prefer a “soft delete” that can be recovered, use trash-put instead of rm.

11. Real‑World Example: A Homelab Server

I run a small NAS with a 2 TB SSD. Over the past year, /var/log grew to 200 MiB because of frequent cron jobs. I set up the script above with a 60‑day threshold and a 5 MiB size filter. After a month, the log directory shrank to 30 MiB, and the SSD health metrics improved.

The cron job runs at 03:00 every Sunday, and I review the daily log file (/var/log/clean_logs_20261109.log) to confirm that only expected files were removed. No service interruptions occurred because I excluded /var/log/nginx and /var/log/mysql.


12. Troubleshooting

  • xargs: rm: No such file or directory
    Usually means the file was deleted by another process between find and rm. It’s harmless; you can ignore it or add -f to silence the error.

  • find: paths must precede expression
    Make sure options like -mtime come after the path (/var/log). The order matters.

  • rm: cannot remove ‘/var/log’: Is a directory
    Double‑check you used -type f. If you accidentally omitted it, rm will try to delete the directory.


13. Wrap‑Up

Using find and xargs to purge old log files is a lightweight, reliable method that fits nicely into a homelab or small server setup. By:

  1. Crafting a precise search predicate,
  2. Verifying the list before deletion,
  3. Using null‑terminated pipelines,
  4. Automating with cron, and
  5. Logging the actions,

you keep your log directories tidy without risking accidental data loss. It plays well with built‑in tools like logrotate and journald, giving you full control over what gets deleted and when.

See also