I have a list of files (say xsl format below) in one directory. I want to keep the last two version of all files. (I can delete the remaing files)


The remaining files present in the directory should be


How can it be achieved?

  • What does the .1 mean in {A}_4.1.xsl? Why does your example keep A_3 and A_4, instead of A_5 and A_6? Similarly, shouldn't you keep B_3 and B_4? – alexis Jan 18 '14 at 18:01
  • Thanks Alex, I updated it. Requirement is like that only. Is that be easily achievable using awk? 4.1 refers to version. – ahamedirshad123 Jan 18 '14 at 18:04
  • 1
    Do any of these versions go over 9? E.g ..._3.11 ? – Anthon Jan 18 '14 at 18:55
  • Nope., but we might get the version like 10.0 – ahamedirshad123 Jan 18 '14 at 20:07

Assuming all the filenames in the current directory follow that pattern, with GNU ls:

ls -rv | awk -F_ '++n[$1]>2' | xargs rm

You can omit the | xargs rm if you want to check what it would remove first.

That assumes the part in {...} doesn't contain space, newline, single quote, double quote, backslash, tab or underscore characters.

The key is the -v option to the GNU implementation of ls that sorts by version number. If you don't have GNU ls, but have zsh, in zsh you can use:

print -rl -- *(nOn)

To achieve the same result.

Now, if the current directory can contain anything and you only want to process the files that are of the form {x}_y.z.xsl where x can be anything and y and z are positive decimal integer numbers, you'd have to write it (zsh syntax):

printf '%s\0' \{*\}_<->.<->.xsl(.nOn) | perl -0 -lne '
  unlink if /\{.*\}/s && ++$n{$&} > 2'

Or using GNU ls and GNU bash instead of zsh:

eval "files=($(ls -rv --quoting-style=shell-always))"
printf '%s\0' "${files[@]}" | perl -0 -lne '
  unlink if /^\{(.*)\}_\d+\.\d+\.xsl\z/s && ++$n{$1} > 2'
  • 1
    whatever happened to parsing the output of ls... – Braiam Jan 18 '14 at 23:53
  • If there were somescript_1.awk, somescript_2.awk and somescript_3.awk, in the same directory it would delete somescript_1.awk. – hlovdal Jan 19 '14 at 10:47
  • @hlovdal, yes, but they don't follow that pattern. I've added a bulletproof version in case the directory contains anything. – Stéphane Chazelas Jan 19 '14 at 11:28
  • @Braiam, here using ls makes sense as we're using its version sorting feature. It's not a problem if the filenames are tamed. Using xargs actually brings more issues than parsing ls. – Stéphane Chazelas Jan 19 '14 at 11:33
  • using variables with awk for number of files to keep: ls -rv | awk -v keepfiles=$keepfiles -F_ '++n[$1]>keepfiles' – Stuart Cardall Jan 30 '19 at 9:50
for i in `ls *_*.?.xsl | sed -n 's/\(.*_\)[0-9]\+\.[0-9]\.xsl/\1/p' | uniq` ; \
do ls $i*.?.xsl | tac | sed 1,2d | xargs rm; done

This does the following

  • Find the prefix for the different sets of files (e.g. {A}, {B} etc)
  • For each prefix list all files and then delete the two last entries (done by reversing the list and deleting the two first entries)
  • Execute rm for the files in the remaining list

This is based on the assumption that the alphabetical sort order is the same as the chronological order. Maybe this is not exactly what you are looking for, but the principle of deleting everything but the two last entries (for some kind of sort order) should be the same.

  • 1
    If there were {C}_8.0.xsl {C}_9.0.xsl {C}_10.0.xsl, it would delete {C}_8.0.xsl {C}_10.0.xsl. – Stéphane Chazelas Jan 18 '14 at 18:54
  • Yes, that is correct. – hlovdal Jan 18 '14 at 19:06
  • I think the downvotes are undeserved. The answer might be incomplete but it is not incorrect! And I very clearly spell out the assumptions made. Or am I wrong? What are some good reasons for downvoting this answer? – hlovdal Jan 19 '14 at 10:35
  • 1
    I'd agree it doesn't deserve downvotes as it works on the sample provided on GNU systems at least. There are a few restrictions that you've not stated (like the xsl files must not be of type directory, their name must not start with - or contain blanks or quotes or wildcards..., cannot be x_1.12.xsl...). It can be simplified (like -r to ls instead of GNU tac, avoid ls which doesn't do anything here since the shell already lists the files. There would be problems with some non-ASCII charcters wrt sorting as well. – Stéphane Chazelas Jan 19 '14 at 11:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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