Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to keep a directory full of log files manageable. Nightly, I want to delete all but the 10 most recent. How can I do this in a single command?

share|improve this question

migrated from Apr 8 '11 at 14:36

This question came from our site for professional and enthusiast programmers.

have a look at logrotate – knittl Apr 8 '11 at 15:26
duplicate:… – michael_n May 31 '15 at 10:29

For a portable and reliable solution, try this:

ls -1tr | head -n -10 | xargs -d '\n' rm -f

The tail -n -10 syntax in one of the other answers doesn't seem to work everywhere (i.e., not on my RHEL5 systems).

And using $() or `` on the command line of rm runs the risk of

  1. splitting file names with whitespace, and
  2. exceeding the maximum commandline character limit.

xargs fixes both of these problems because it'll automatically figure out how many args it can pass within the character limit, and with the -d '\n' it will only split at the line boundary of the input. Technically this can still cause problems for filenames with a newline in them, but that's far less common than filenames with spaces, and the only way around the newlines would be a lot more complicated, probably involving at least awk, if not perl.

If you don't have xargs (old AIX systems, maybe?) you could make it a loop:

ls -1tr | head -n -10 | while read f; do
  rm -f "$f"

This will be a bit slower because it spawns a separate rm for each file, but will still avoid caveats 1 and 2 above (but still suffers from newlines in file names).

share|improve this answer
@HaukeLaging: From the head(1) man page: -n, --lines=[-]K print the first K lines instead of the first 10; with the leading '-', print all but the last K lines of each file – Isaac Freeman May 15 '13 at 6:06
On Solaris 10 head and xargs give errors. Correct options are head -n 10 and xargs rm -f. Full command is ls -1tr ./ | head -n 10 | xargs rm -rf – DmitrySandalov Oct 31 '14 at 13:36
Note the ls -1tr is the number ONE not the letter "L". – shonky linux user Aug 27 '15 at 7:51
It should also be noted that newlines are rare but valid characters in ext filenames. This means that if you have the files "that", and "that\nthing", if this script hits "that\nthing", it'll delete "that", error when it couldn't delete "thing", and leave "that\nthing" (the intended target) unaffected. – Synthead Apr 15 at 23:26
@Synthead I believe I "noted" that fact fairly clearly in my post. Do you have a better solution that also accounts for newlines in filenames which is portable and simple? – Isaac Freeman May 7 at 18:22

The code you'd want to include in your script is

 rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)

The -1 (numeric one) option prints each file on a single line, to be safe. The -f option to rm tells it to ignore non-existent files for when ls returns nothing.

share|improve this answer
Original poster, here. I tried this command, but it doesn't work--I get the error "rm: missing operand" – user75814 Apr 10 '11 at 13:50
Did you use the correct path? Obviously /path/to/your/logs is just made up for you to enter the correct path. To find the bug execute the parts ls -t /path/... and ls -t /path/... | tail -n +11 alone and check if the result is correct. – Daniel Böhmer Apr 11 '11 at 9:01
@HaukeLaging I am quite sure you got something wrong. Mind the + before the number. It makes tail not print the last n elements but all elements beginning from the n'th. I checked in again and the command should definitely remove only elements older than 10 most recent files under all circumstances. – Daniel Böhmer Mar 14 '13 at 14:01
@halo Indeed, sorry. – Hauke Laging Mar 14 '13 at 17:41
Using $() and ``` `` ``` on the commandline, especially with a command that lists filenames runs the risk of splitting filenames with spaces in them in to separate arguments. See my answer below for a safer and more portable solution. – Isaac Freeman Aug 4 '13 at 23:38

A tool like logrotate does this for you. It makes log management much easier. You can also include additional cleanup routines shuch as halo sugggested.

share|improve this answer

Apparently parsing ls is evil,

If each file is created daily and you want to keep files created within the last 10 days you can do:

find /path/to/files -mtime 10 -delete

Or if each file is created arbitrarily:

find /path/to/files -maxdepth 1 -type f -printf '%Ts\t%P\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf
share|improve this answer

I modified Isaac's approach a little bit.

It now works with a desired path:

ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
share|improve this answer


ls -1t | (i=0; while read f; do
  if [ $i -lt 10 ]; then
    rm -f "$f"

This skips the 10 newest als deletes the rest. logrotate may be better, I just want to correct the wrong shell related answers.

share|improve this answer

From here:

#! /bin/sh
# keepnewest
# Simple directory trimming tool to handle housekeeping
# Scans a directory and deletes all but the N newest files
# Usage: cleanup <dir> <number of files to keep>
# v 1.0 Piers Goodhew 1/mar/2007. No rights retained.

if [ $# -ne 2 ]; then
  echo 1>&2 "Usage: $0 <dir> <number of files to keep>"
  exit 1

cd $1
files_in_dir=`ls | wc -l`
files_to_delete=`expr $files_in_dir - $2`
if [ $files_to_delete -gt 0 ]; then
  ls -t | tail -n $files_to_delete | xargs rm
  if [ $? -ne 0 ]; then
    echo "An error ocurred deleting the files"
    exit 1
    echo "$files_to_delete file(s) deleted."
  echo "nothing to delete!"
share|improve this answer
Thanks for providing this answer. While providing code like this is helpful, it also helps to provide some additional information about how it might be used or what the code does. You can use the edit button to make future improvements to your post. – nhinkle Mar 21 '13 at 5:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .