ampath 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 27 December 2011
  5. # Edit: 18 February 2012
  6. # Edit: 16 November 2021
  7. # https://github.com/trizen
  8. # Find files which have the exact or almost the exact name in a path.
  9. use 5.010;
  10. use strict;
  11. use warnings;
  12. use Getopt::Long;
  13. use experimental qw(smartmatch);
  14. sub usage {
  15. print <<"HELP";
  16. usage: $0 [options] [dir]
  17. options:
  18. --approx=i : amount of approximateness (default: 0)
  19. --hidden! : verify hidden files and folders (default: false)
  20. example: $0 --approx=4 /my/dir
  21. HELP
  22. exit 0;
  23. }
  24. my $show_hidden_files;
  25. my $approximate_n;
  26. GetOptions(
  27. 'approximate=i' => \$approximate_n,
  28. 'hidden!' => \$show_hidden_files,
  29. 'help|h' => \&usage,
  30. )
  31. or die "Error in command-line arguments!";
  32. if (defined $approximate_n) {
  33. $approximate_n += 1;
  34. }
  35. my @files;
  36. sub locate_files {
  37. foreach my $dir (@{$_[0]}) {
  38. $dir = readlink $dir and chop $dir if -l $dir;
  39. next unless opendir(my $dir_h, $dir);
  40. my @dirs;
  41. while (defined(my $file = readdir $dir_h)) {
  42. if ($show_hidden_files) {
  43. if ($file eq '.' || $file eq '..') {
  44. next;
  45. }
  46. }
  47. else {
  48. next if chr ord $file eq '.';
  49. }
  50. if (-d "$dir/$file") {
  51. push @dirs, "$dir/$file";
  52. }
  53. elsif (-f _) {
  54. push @files, {lc $file, "$dir/$file", 'file', lc $file};
  55. }
  56. }
  57. closedir $dir_h;
  58. locate_files(\@dirs);
  59. }
  60. }
  61. sub editdist {
  62. my %h;
  63. $h{$_}++ for split //, lc shift;
  64. $h{$_}-- for split //, lc shift;
  65. my $t = 0;
  66. $t += ($_ > 0 ? $_ : -$_) for values %h;
  67. $t;
  68. }
  69. sub find_similar_names {
  70. my ($name, $array_ref) = @_;
  71. my (@names) =
  72. sort { $a->[1] <=> $b->[1] } grep { defined } map {
  73. my $d = editdist($_, $name);
  74. $d < $approximate_n ? [$_, $d] : undef;
  75. } grep { $_ ne $name } @$array_ref;
  76. if (@names) {
  77. my $best = $names[0][1];
  78. @names = map { $_->[0] } grep { $_->[1] == $best } @names;
  79. }
  80. \@names;
  81. }
  82. sub diff {
  83. my %alike;
  84. my %table;
  85. my @found;
  86. if (defined $approximate_n) {
  87. my (@names) = map { $_->{'file'} } @files;
  88. foreach my $file (@files) {
  89. my (@names) =
  90. map { $_->{'file'} }
  91. grep {
  92. my $length_1 = length $_->{'file'};
  93. my $length_2 = length $file->{'file'};
  94. ($length_1 <= $length_2 + $approximate_n) and ($length_1 >= $length_2 - $approximate_n)
  95. or ($length_1 == $length_2)
  96. if ($_->{'file'} ne $file->{'file'});
  97. } @files;
  98. push @{$table{$file->{$file->{'file'}}}}, @{find_similar_names $file->{'file'}, \@names};
  99. }
  100. foreach my $array_1_ref (values %table) {
  101. next unless $array_1_ref;
  102. while (my ($file, $array_2_ref) = each %table) {
  103. if (@{$array_2_ref} and $array_1_ref ~~ $array_2_ref) {
  104. $alike{$file} = ();
  105. }
  106. }
  107. }
  108. return map { $_->[1] }
  109. sort { $a->[0] cmp $b->[0] }
  110. map { [lc(substr($_, rindex($_, '/'))), $_] }
  111. keys %alike;
  112. }
  113. foreach my $file (@files, @files) {
  114. $alike{$file->{$file->{'file'}}} = () if $table{$file->{'file'}}++ >= 2;
  115. }
  116. return map { $_->[1] }
  117. sort { $a->[0] cmp $b->[0] }
  118. map { [lc(substr($_, rindex($_, '/'))), $_] }
  119. grep { length } keys %alike;
  120. }
  121. foreach my $arg (@ARGV) {
  122. $arg =~ s[(?<=.)/+$][];
  123. my (@dir) = (-d $arg) ? $arg : next;
  124. local $, = "\n";
  125. say diff(locate_files(\@dir));
  126. undef @files;
  127. }