10

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?

AgentConundrum
  • 20,288
  • 6
  • 64
  • 99
nivanka
  • 1,352
  • 6
  • 23
  • 36

3 Answers3

17

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
AgentConundrum
  • 20,288
  • 6
  • 64
  • 99
  • Hi thank you for the response, but still I get the file names only, one of my main needs is to run this code from any dir of the server and remove the files in that var/path/to/folder this works well if I am in the same folder var/path/to/folder – nivanka Dec 15 '10 at 08:06
  • @nivanka: That's really weird. Are you specifying a relative or absolute path? You need to specify an absolute path if you want to run this from any directory on the server. Can you copy/paste the *exact* command you're using? – AgentConundrum Dec 15 '10 at 08:12
  • hi, this is what I do ls -t1 /var/path/to/folder | tail -n +4 | xargs rm -r – nivanka Dec 15 '10 at 08:55
  • @nivanka: Apparently I was wrong about passing absolute paths resulting in full-path output. Sorry about that. I guess the only way you're going to be able to do it is to store your current path in a variable, `cd` to `/var/path/to/folder`, run the code i gave you, then `cd` back to your original path using the variable. That's the best I can do, sorry. – AgentConundrum Dec 15 '10 at 10:26
  • hey thanks for that, I dont know whether I can do a CD there, as I am planning to run this on capistrano. anyway thanks for the support – nivanka Dec 15 '10 at 14:29
  • @nivanka: If you can't use `cd`, then you could find the full path using `find`. See my edit. – AgentConundrum Dec 16 '10 at 00:05
  • I don't believe -1 is necessary in this case because ls functions differently depending on if the output is a tty or not - see http://unix.stackexchange.com/a/22164/28597 – JZeolla Feb 09 '16 at 19:28
  • // , This really works, on RHEL 7, at least. To test, without deleting anything, run this command: `ls -t1 /opt/consul/snapshots | tail -n +4 | xargs echo deleted all of the following ` – Nathan Basanese Nov 05 '18 at 18:37
4

Below is a useful way of doing the task.......!!

for Linux and HP-UX:

ls -t1 | tail -n +50 | xargs rm -r # to leave latest 50 files/directories.

for SunOS:

rm `(ls -t |head -n 100; ls)|sort|uniq -u`

0

Hi I found a way to do this we can use the unix &&

so the command will look like this

cd /var/path/to/folder && ls -t1 /var/path/to/folder | tail -n +4 | xargs rm -r
nivanka
  • 1,352
  • 6
  • 23
  • 36