user3375339
user3375339

Reputation: 13

bash command/script to delete older files version

I have 1 directory with a lot of pdf files. This files are generated by another script that renames files with a progressive number for new version: (example)

newyork_v1.pdf
newyork_v2.pdf
newyork_v3.pdf
miami_v1.pdf
miami_v2.pdf
rome_v1.pdf

The version number is relative to the file, some files are a version 1, someone at version 2 etc like in example. Some files stay in version 1 for all own life, some files may grow to 10th version.

After copying this directory in a temp directory I'd like to delete old version for all files, in the example must remain:

newyork_v3.pdf
miami_v2.pdf
rome_v1.pdf

I try sort and delete by ls and sort command but I do not get the desired result, i try:

ls | sort -k2 -t_ -n -r | tail -n +2 | xargs rm

with this command stay only rome_v1.pdf

command or script are indifferent, can anyone help me?

Upvotes: 1

Views: 1469

Answers (3)

Timmah
Timmah

Reputation: 2121

If you can use GNU ls, you can try below:

for p in $(ls -v *.pdf | cut -d_ -f1 | sort | uniq); do
    ls -v $p* | head -n -1 | xargs -I{} rm {} 2>/dev/null
done

The -v flag of GNU ls sorts the files 'naturally' ie. in your case:

miami_v1.pdf
miami_v2.pdf
newyork_v1.pdf
newyork_v2.pdf
newyork_v3.pdf
newyork_v10.pdf #Added to show ls -v in action
rome_v1.pdf

We then loop through each uniq prefix and delete everything other than the last file which matches the prefix.

Result:

miami_v2.pdf
newyork_v10.pdf
rome_v1.pdf

Update:

Changed xargs to handle whitespace and special characters.

Upvotes: 2

Amit
Amit

Reputation: 20456

for file in $(ls *.pdf | awk -F'_' '{print $1}' | sort -u)
do
    count=$(ls ${file}* | wc -l)
    if [ ${count} -gt 1 ]; then
        ls -rv ${file}* | tail -$(($count-1)) | xargs rm
    fi
done

Upvotes: 4

Lee Duhem
Lee Duhem

Reputation: 15121

This Perl script can be used to filter out the old file names:

#!/usr/bin/perl

use warnings;
use strict;

my %files;
my @old_files;
while (<DATA>) {
    chomp;
    my ($name, $version, undef) = split /_v|\./, $_;
    if (!$files{$name}->{version}) {
        $files{$name}->{version} = $version;
        $files{$name}->{name} = $_;
        next;
    }
    if ($files{$name}->{version} < $version) {
        push @old_files, $files{$name}->{name};
        $files{$name}->{version} = $version;
        $files{$name}->{name} = $_;
    }
}

foreach my $file (@old_files) {
    print "$file\n";
}

__DATA__
newyork_v1.pdf
newyork_v2.pdf
newyork_v3.pdf
miami_v1.pdf
miami_v2.pdf
rome_v1.pdf

Upvotes: 0

Related Questions