file-mover.pl 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 23 August 2015
  5. # Website: https://github.com/trizen
  6. # Sort and move a list of file names into a given directory
  7. use 5.016;
  8. use strict;
  9. use warnings;
  10. use open IO => ':utf8', ':std';
  11. use File::Copy qw(move);
  12. use File::Basename qw(basename);
  13. use File::Spec::Functions qw(catfile);
  14. use Getopt::Long qw(GetOptions);
  15. my $reverse = 0; # bool
  16. my $sort_by = 'none'; # string
  17. my $output_dir; # string
  18. my $move = 'none'; # string
  19. my %sorts = (
  20. none => sub { },
  21. name => sub { $a cmp $b },
  22. iname => sub { fc($a) cmp fc($b) },
  23. length => sub { length($a) <=> length($b) },
  24. size => sub { (-s $a) <=> (-s $b) },
  25. atime => sub { (stat($a))[8] <=> (stat($b))[8] },
  26. mtime => sub { (stat($a))[9] <=> (stat($b))[9] },
  27. ctime => sub { (stat($a))[10] <=> (stat($b))[10] },
  28. );
  29. sub help {
  30. print <<"EOT";
  31. usage: $0 [options] < [input.txt]
  32. options:
  33. -s --sort-by=s : sort the files by:
  34. name -> sort by filename
  35. iname -> sort by filename case-insensitively
  36. length -> sort by the length of the filename
  37. size -> sort by the size of the file
  38. atime -> sort by file access time
  39. mtime -> sort by file modification time
  40. ctime -> sort by file inode change time
  41. none -> don't do any sorting (default)
  42. -r --reverse! : reverse the sorting
  43. -o --out-dir=s : move the files into this directory
  44. -m --move=s : move the files as follows:
  45. first -> moves the first n-1 files
  46. last -> moves the last n-1 files
  47. all -> moves all files
  48. none -> don't move any file (default)
  49. example:
  50. $0 --sort-by=mtime --move=last --out-dir=/tmp < files.txt
  51. EOT
  52. exit 0;
  53. }
  54. GetOptions(
  55. 'm|move=s' => \$move,
  56. 'r|reverse!' => \$reverse,
  57. 'o|out-dir=s' => \$output_dir,
  58. 's|sort-by|sortby=s' => \$sort_by,
  59. 'h|help' => \&help,
  60. )
  61. or die("error in command line arguments");
  62. my $sort_code = $sorts{lc($sort_by)} // die "Invalid value `$sort_by' for option `--sort-by'";
  63. if ($move ne 'none') {
  64. if (defined($output_dir)) {
  65. if (not -d $output_dir) {
  66. die "Invalid value `$output_dir' for option `--out-dir' (requires an existent directory)";
  67. }
  68. }
  69. else {
  70. die "Please add the `--out-dir' option, in order to `--move` files";
  71. }
  72. }
  73. sub process_files {
  74. my (@files) = @_;
  75. @files = do {
  76. my %seen;
  77. grep { !$seen{$_}++ } @files;
  78. };
  79. if ($sort_by ne 'none') {
  80. @files = sort $sort_code @files;
  81. }
  82. if ($reverse) {
  83. @files = reverse(@files);
  84. }
  85. my @all_files = @files;
  86. if ($move eq 'none') {
  87. @files = ();
  88. }
  89. elsif ($move eq 'first') {
  90. @files = @files[0 .. $#files - 1];
  91. }
  92. elsif ($move eq 'last') {
  93. @files = @files[1 .. $#files];
  94. }
  95. elsif ($move eq 'all') {
  96. ## ok
  97. }
  98. else {
  99. die "Invalid value `$move' for `--move`";
  100. }
  101. my %table;
  102. @table{@files} = ();
  103. foreach my $file (@all_files) {
  104. print $file;
  105. if (exists $table{$file}) {
  106. my $basename = basename($file);
  107. my $dest = catfile($output_dir, $basename);
  108. print " -> $dest";
  109. if (-e $dest) {
  110. print " (error: already exists)";
  111. }
  112. else {
  113. if (move($file, $dest)) {
  114. print " (OK)";
  115. }
  116. else {
  117. print " (error: $!)";
  118. }
  119. }
  120. }
  121. print "\n";
  122. }
  123. if (@all_files) {
  124. say "-" x 80;
  125. }
  126. }
  127. my @files;
  128. while (defined(my $line = <>)) {
  129. chomp($line);
  130. if (-e $line) {
  131. push @files, $line;
  132. }
  133. elsif (@files) {
  134. process_files(@files);
  135. @files = ();
  136. }
  137. }
  138. process_files(@files) if @files;