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
    Commented Jan 18, 2014 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. Commented Jan 18, 2014 at 18:04
  • 1
    Do any of these versions go over 9? E.g ..._3.11 ?
    – Anthon
    Commented Jan 18, 2014 at 18:55
  • Nope., but we might get the version like 10.0 Commented Jan 18, 2014 at 20:07

2 Answers 2


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
    Commented Jan 18, 2014 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
    Commented Jan 19, 2014 at 10:47
  • @hlovdal, yes, but they don't follow that pattern. I've added a bulletproof version in case the directory contains anything. Commented Jan 19, 2014 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. Commented Jan 19, 2014 at 11:33
  • using variables with awk for number of files to keep: ls -rv | awk -v keepfiles=$keepfiles -F_ '++n[$1]>keepfiles' Commented Jan 30, 2019 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. Commented Jan 18, 2014 at 18:54
  • Yes, that is correct.
    – hlovdal
    Commented Jan 18, 2014 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
    Commented Jan 19, 2014 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. Commented Jan 19, 2014 at 11:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .