Monday 12 December 2011 — This is almost 13 years old. Be careful.
This is one of those conceptually easy tasks that seems frequently required, and yet needs a complex incantation to accomplish. I have a series of files, and it will grow over time, and I want to clean them up, but keep the most recent N files.
After poking around the Google, I found this for deleting PATTERN, but keeping the five most recent:
ls -t1 PATTERN | tail -n +6 | xargs -r rm -r
That’s dash-t-one on the ls command. Or, in words:
- List files matching PATTERN, in descending order of modification time, in one column,
- Pass through all the trailing lines, starting with the sixth from the beginning,
- Bundle all those filenames into an “rm -r” command, but not if there are none.
That wasn’t so hard, was it??
Comments
function rm_old_files { ls -td1 "$@"| tail -n6 | while read f; do rm -i $f; done }
Using a 'read-while' loop like this lets you pipe output (as opposed to using 'find'), and without un-escaped-space problems found in other loops.
also, In ZSH you could do:
rm -i ./(.Oa[1,6])
rm -i ./PATTERN(.Oa[1,6])
I'm not sure how to re-edit my post, or add formatting...
@Chris: excellent point, -- can only make things safer.
@Ed: another good point, I should have thought about the '1' myself.
@void: in my case, the things to delete were not simple text files, but entire trees, which means I need -d on the ls command also.
I find the tail-piped-to-xargs style of solution more memorable and readable than having to work out while-read loops in shell, but that's possibly a matter of muscle memory. I use the former style much more frequently.
Personally I think I'd do this with pipes, though, it's easier to maintain that way.
You could also use GNU Parallel as sugested here
@Graham
Ah, my examples just deletes the last 6, and the ZSH snippet doesn't delete directories; Your ZSH snippet is right, and the shell function would be: for another point of safety, I've used 'IFS= read -r' as well.
Also, I've discovered a weaknesss; You cannot use '-i' with rm, (or use any interactive command) as that will conflict with 'read'...
@Anon
I prefer not to use find, but then there's also find2perl :-D
I hadn't run across the program before and it seems like a very nice tool -- running tools in parallel, local and remote execution, etc, etc...
Its Wikipedia article links to a couple of very nice introductory videos: http://commons.wikimedia.org/wiki/GNU_parallel
Add a comment: