Wednesday, February 7, 2024

[SOLVED] how to delete all files except the latest three in a folder

Issue

I have a folder which contains some subversion revision checkouts (these are checked out when running a capistrano deployment recipe).

what I want to do really is that to keep the latest 3 revisions which the capistrano script checkouts and delete other ones, so for this I am planning to run some command on the terminal using a run command, actually capistrano hasn't got anything to do here, but a unix command.

I was trying to run a command to get a list of files except the lastest three and delete the rest, I could get the list of files using the following command.

(ls -t /var/path/to/folder |head -n 3; ls /var/path/to/folder)|sort|uniq -u|xargs

now if I add a rm -Rf to the end of this command it returns me with file not found to delete. so thats obvious because this returns only the name of the folder, not the full path to the folder.

is there anyway to delete these files / folders using one unix command?


Solution

Alright, there are a few things wrong with your script.

First, and most problematically, is this line:

ls -t /var/path/to/folder |head -n 3;

ls -t will return a list of files in order of their last modification time, starting with the most recently modified. head -n 3 says to only list the first three lines. So what this is saying is "give me a list of only the three most recently modified files", which I don't think is what you want.

I'm not really sure what you're doing with the second ls command, but I'm pretty sure that's just going to concatenate all the files in the directory into your list. That means when it gets sorted and uniq'ed, you'll just be left with an alphabetical list of all the files in that directory. When this gets passed to something like xargs rm, you'll wipe out everything in that directory.

Next, sort | uniq doesn't need the uniq part. You can just use the -u switch on sort to get rid of duplicates. You don't need this part anyway.

Finally, the actual removal of the directory. On that part, you had it right in your question: just use rm -r

Here's the easiest way I can think to do this:

ls -t1 /var/path/to/folder | tail -n +4 | xargs rm -r

Here's what's happening here:

  • ls -t1 is printing a list, one file/directory per line, of all files in /var/path/to/folder, ordering by the most recent modification date.
  • tail -n +4 is printing all lines in the output of ls -t1 starting with the fourth line (i.e. the three most recently modified files won't be listed)
  • xargs rm -r says to delete any file output from the tail. The -r means to recursively delete files, so if it encounters a directory, it will delete everything in that directory, then delete the directory itself.

Note that I'm not sorting anything or removing any duplicates. That's because:

  • ls only reports a file once, so there are no duplicates to remove
  • You're deleting every file passed anyway, so it doesn't matter in what order they're deleted.

Does all of that make sense?

Edit:

Since I was wrong about ls specifying the full path when passed an absolute directory, and since you might not be able to perform a cd, perhaps you could use tail instead.

For example:

 ls -t1 /var/path/to/folder | tail -n +4 | xargs find /var/path/to/folder -name $1 | xargs rm -r


Answered By - AgentConundrum
Answer Checked By - Mary Flores (WPSolving Volunteer)