Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm looking for a Bash script that will go into a list of directories and delete all but the four most recently created files.

How can I do this?

share|improve this question
    
How recent is recent? Is it a predefined time period? –  bahamat Aug 16 '11 at 4:20
    
Do you want the script to keep the four most recent files as per the whole list of directories or individually for each directory? Also, do you want it to operate recursively? –  artistoex Sep 16 '11 at 8:41
    
i want the rm command to go into each and every folder and delete all but 4 (of the latest files) –  Marv1n Sep 17 '11 at 10:48
add comment

5 Answers

ls -t | sed '1,4d' | xargs echo rm

Remove the echo when you're satisfied that's the result you want.

If you have filenames with spaces, more work is required.

share|improve this answer
    
hey mate, ran this command but it just listed the directory names –  Marv1n Aug 16 '11 at 4:15
1  
We can replace sed '1,4d' with tail -n +5. –  jfgagne Aug 16 '11 at 10:28
    
@Marvin, do you have any aliases, such as for ls? –  glenn jackman Aug 16 '11 at 11:20
    
@Marvin: remove the echo as explained in the answer. –  Stéphane Gimenez Oct 1 '11 at 23:38
add comment

Do you want to keep the four most recent files in each directory, or the four most recent files in ANY directory?

To solve the first problem, you would use find to list each directory, then in each, remove all but the four most recent files. This isn't too hard.

To solve the second problem takes a bit more thought, but is actually easier to write.

Basically, find every file recursively. Call the "stat" command returning the file's modification time and name. Sort this descending numerically, and skip the first four files, which are the most recent.

Then remove the leading timestamps, and remove the resulting list of filenames.

Something like (untested):

#!/bin/bash

find "$@" -type f -print0 \
| xargs -0 stat -c$'%Y\t%n' \
| sort -rn \
| awk -F$'\t' 'NR > 4 {print $2}' \
| while read f; do
    echo rm -v "${f}"
  done

This should work, though you'll want to remove the 'echo' in the while loop to make it effective. Test it carefully first!

share|improve this answer
    
Thanks for the reply! I want to keep 4 most recent files in each directory. Basically it's a backups folder for various websites I manage. Each folder is a website. I've got a daily backup script that rips each site (including the db) into a neat little jpa file. –  Marv1n Aug 19 '11 at 5:23
    
hey mate, i've ran this script but it managed to delete most of the files in each subfolder for extra info i've got the script in /backup/ and the rest of the folder is as shown /backup/website1/file1 /backup/website1/file2 /backup/website1/file3 /backup/website2/file1 /backup/website2/file2 /backup/website2/file3 /backup/website2/file4 and so on and so on –  Marv1n Aug 30 '11 at 1:55
add comment

I realise this isn't quite what you're asking, but for this kind of backup I prefer to rotate the log files before creating the new one. It's a bit more explicit, and much simpler to code, like this:

#!/bin/bash

#Archive old backups
move () {
  if [ -e $1 ]
  then
    echo "Archiving old backups: $1 to $2"
    mv -f $1 $2 || echo "FAILED"
  fi
}

#Bump each backup +1
rm -rf backup.4
move backup.3.tgz backup.4.tgz
move backup.2.tgz backup.3.tgz
move backup.1.tgz backup.2.tgz
move backup.tgz backup.1.tgz

#Now create today's backup
...
share|improve this answer
add comment

This command should work

find PATH1 PATH2 PATH3 -type f  -printf '%T@ %p\n'|sort -nr|tail -n+5|cut -f 2- -d " "|xargs -i rm {}

If you don't want the command to delete files recursively, add the option -maxdepth 1 before -type f

The command recursively prints each file with its last modification date (find PATH1 PATH2 PATH3 -type f -printf '%T@ %p\n'), then sorts the list by date (sort -nr), then skips the first four entries (tail -n+5). Finally, the time information is stipped off (cut -f 2- -d " ") and the result subsequently passed to xargs which generates and executes the corresponding rm command.

share|improve this answer
add comment

The most simplest method:

for d in dir1 dir2 dir3; do
  rm -vf `ls -1t $d | head -n-4` 
done
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.