#!/usr/bin/perl # # rm1 - remove duplicate downloads among files # # $Id$ use warnings; use strict; use File::Basename qw(dirname basename); use File::Compare qw(compare); use File::stat qw(stat); my %opt = (); while ( @ARGV && ( my ($o) = $ARGV[0] =~ /^-(.*)/ ) ) { ++$opt{$o}; shift(@ARGV); } sub original_for { # return the filenames without infixes (1), (2), etc. $_[0] =~ s#\s*\(\d+\)\.#.#r; } my %original = (); foreach my $f (@ARGV) { if ( -f $f && -r $f ) { ++$original{ original_for($f) }; } elsif (!-d $f) # don't warn for directories { warn "not a plain file or not readable, skipped: $f\n"; } } foreach my $o ( sort keys %original ) { warn "deduplicating for: $o\n" if $opt{v}; my $dir = dirname($o); if ( opendir( my $dh, $dir ) ) { my $o_base = basename($o); my $o_stat = stat($o); my %identical; foreach my $f ( readdir($dh) ) { next if original_for($f) ne $o_base; my $f_stat = stat($f); my $abs_f = "$dir/$f" =~ s#^\./##r; if ( !defined $o_stat ) { # $o does not exist if ( $opt{n} ) { warn "would rename $abs_f to $o\n" if $opt{v}; } else { warn "renaming $abs_f to $o\n" if $opt{v}; rename( $abs_f, $o ) or die "Aborting! Rename failed: $@\n"; } $o_stat = $f_stat; } elsif ( $f_stat->dev eq $o_stat->dev && $f_stat->ino eq $o_stat->ino ) { # $f is $o 1; } elsif ( $f_stat->size ne $o_stat->size ) { # $f is different from $o 1; } elsif ( compare( $abs_f, $o ) ) { # $f is different from $o 1; } else { # $f is not $o, but identical to it if ( $opt{n} ) { warn "identical to $o, would remove: $abs_f\n" if $opt{v}; } else { warn "identical to $o, removing: $abs_f\n" if $opt{v}; unlink($abs_f) or die "Aborting! Removal failed: $@\n"; } } } closedir($dh); } else { warn "cannot open parent directory, skipping: $o\n"; } }