#!/usr/bin/perl -w # # Move loose files into appropriate directories # # Written ????-??-?? by Steven J. DeRose, sderose@acm.org. # 2010-03-19: clean up a bit. use strict; my $mvoptions = "-n"; # Don't overwrite. my $letter = ""; my $tokens = 0; while ($ARGV[0] =~ m/^-/) { if ($ARGV[0] eq "-v") { $verbose = 1; } elsif ($ARGV[0] eq "-h") { showUsage(); exit; } elsif ($ARGV[0] eq "-l") { shift; $letter = $ARGV[0]; } elsif ($ARGV[0] eq "-t") { $tokens = 1; } shift; } (-d $ARGV[0]) || die "No '$ARGV[0]' directory to gather from.\n"; my $src = $ARGV[0]; # Make list of all non-short tokens #my $lCmd = "ls $src | sed -e 's|.*/||' -e 's/[-_0-9]/_/g' -e 's/\\.jpg//' " # . " | tr '_' '\012' | tr 'A-Z' 'a-z' | grep '....' | sort | uniq"; if ($tokens) { print "$srcList"; exit; } ##### Get list of directories within current dir my @dirs = `ls -F`; my $ndirs = scalar @dirs; ##### Just list all the src files. my @srcList = `ls $src | sed 's|.*/||'`; print "Source files found: " . (scalar @srcList) . ".\n"; for (my $i=0; $i<(scalar @srcList); $i++) { chomp($srcList[$i]); } # Grab files from source dir that match up with local dir names we found. my $grandTotal = 0; my $n = 0; for my $dn (@dirs) { $n++; # chomp and drop final '/' $dn =~ s|/\n||; (my $d = $dn) =~ s/\*.*$//; # allow suffixes # If -letter option, do only that initial letter/portion if ($letter ne "" && ($d !~ m/^$letter/i)) { next; } if (length($d) < 4) { print "Skipping dir '$d' with short name.\n"; next; } my @dTokens = split(/_/,$d); # print "Starting $n of $ndirs: $d (" . (scalar @srcList) . " files left).\n"; # Now move each file whose name contains all the dir tokens, # to the corresponding directory. $total = 0; my $expr = join(".?",@dTokens); my $expr2 = join(".?", (reverse @dTokens)); my $total = 0; my $nsrc = scalar @srcList; for (my $i=0; $i<$nsrc; $i++) { my $f = $srcList[$i]; ($f eq "") && next; if (($f =~ m/$expr/i) || ($f =~ m/$expr2/i)) { ($verbose) && print "Move #$total: '$f' to $dn/\n"; system "mv '$src/$f' '$dn/'" || print "Move of $f failed\n"; $total++; $srcList[$i] = ""; } } my $msg = ""; if ($total > 0) { $msg = sprintf("%5d total files to", $total); $grandTotal += $total; } print sprintf("%3d/%3d %20s %s.\n", $n, $ndirs, $msg, $d); } print "Done, grand total of $grandTotal files moved.\n"; exit; ####################### sub xxx { # Do a quick check to see if each token of dir name occurs at all. my $fail = ""; for my $dt (split(/_/, lc($d))) { if (index($srcList, " $dt ") < 0) { $fail = $dt; last; } } if ($fail ne "") { print " Token '$fail' of '$d' failed.\n"; next; } if (($sur ne "") && (scalar @surs == 0)) { print " Found no '[a-z]$sur', so skipping '$d'\n"; next; } # Make versions with _ gone, name reversed, and lowercased. my @names = (); if (index($d,"_") >= 0) { (my $d1 = $d) =~ s/_/\?/g; push @names, $d1; (my $d2 = $d) =~ s/_//g; push @names, $d2; (my $d3 = $d) =~ s/^(.*)_(.*)$/$2\?$1/; push @names, $d3; (my $d4 = $d3) =~ s/\?//g; push @names, $d4; } else { push @names, $d; } # Add the lowercase versions, too my $limit = scalar @names; for (my $i=0; $i<$limit; $i++) { push @names, lc($names[$i]); } for my $name (@names) { my $nm = $name; if ($verbose) { print "listing for '$src/*$nm*.jpg'.\n"; system "ls $src/*$nm*.jpg 2>/dev/null"; } $count = `ls $src/*$nm*.jpg 2>/dev/null | wc -l`; chomp $nm; $count =~ s/^\s*([0-9]+)\s.*$/$1/; if ($count > 0) { system "mv $mvoptions $src/*$nm*.jpg $d/"; $total += $count; } } } ############################################################################### # sub showUsage { warn " =head1 Usage gather [options] otherdir For each sub-directory of the current directory, gathers any files in 'otherdir' whose names match up with it, and moves them to it. =head1 Options =over =item * B<-l string> Only do directories beginning with 'string' (ignores case). =item * B<-t> Just show list of tokens from src dir filenames =item * B<-v> Verbose. Matching: Directory named are X_Y, and any file will match if its name contains: X_Y XY Y_X YX x_y xy y_x yx Does not catch X or Y alone. "; } ############################################################################### # sub showLicense { print " This work by Steven J. DeRose is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. For further information on this license, see http://creativecommons.org/licenses/by-sa/3.0/. The author's present email is sderose at acm.org. For the most recent version, see http://www.derose.net/steve/utilities/. =cut "; }