Guest User

Untitled

a guest
Jul 20th, 2018
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.26 KB | None | 0 0
  1. #!/usr/bin/env perl
  2. use common::sense;
  3. use Getopt::Long qw(:config gnu_compat no_bundling no_ignore_case);
  4. use Pod::Usage;
  5. use File::Find;
  6. use Readonly;
  7. use Data::Dumper;
  8. use Time::Piece;
  9.  
  10.  
  11.  
  12. # Constants for timestamps.
  13. Readonly::Scalar my $TS_ATIME => 0;
  14. Readonly::Scalar my $TS_MTIME => 1;
  15. Readonly::Scalar my $TS_CTIME => 2;
  16. Readonly::Scalar my $OL_OLDEST => 0;
  17. Readonly::Scalar my $OL_LATEST => 1;
  18. Readonly::Array my @TS_NAME => qw(
  19. atime
  20. mtime
  21. ctime
  22. );
  23. Readonly::Array my @OL_NAME => qw(
  24. oldest
  25. latest
  26. );
  27. Readonly::Array my @STAT_INDEX => (
  28. 8,
  29. 9,
  30. 10
  31. );
  32.  
  33.  
  34.  
  35. sub usage () {
  36. print STDERR "\n\n";
  37. pod2usage(-verbose => 1, -output => \*STDERR);
  38. }
  39.  
  40. sub uneval {
  41. local $Data::Dumper::Terse = 1;
  42. local $Data::Dumper::Indent = 1;
  43. Dumper(@_);
  44. }
  45.  
  46. {
  47. my $verbose = 0;
  48.  
  49. sub set_verbose {
  50. $verbose = shift;
  51. }
  52.  
  53. sub verbose {
  54. $verbose and say STDERR "[verbose] ", @_;
  55. }
  56. }
  57.  
  58. sub get_timestamps {
  59. my ($search_dirs, $ts_checklist, $oldest_or_latest, $check_directory, $follow_symlinks) = @_;
  60. my @ts_result = (undef) x 3;
  61.  
  62. find(
  63. {
  64. wanted => sub {
  65. my @stat = stat $_;
  66. return if !$check_directory && -d _;
  67. verbose "processing $_...";
  68.  
  69. for my $ts (@$ts_checklist) {
  70. for my $ol (@$oldest_or_latest) {
  71. my $time = $stat[$STAT_INDEX[$ts]];
  72.  
  73. unless (defined $ts_result[$ts]) {
  74. $ts_result[$ts] = [({
  75. time => $time,
  76. file => $_,
  77. }) x 2];
  78. next;
  79. }
  80.  
  81. my $current = $ts_result[$ts][$ol]{time};
  82. if ($ol == $OL_LATEST ? $time > $current : $time < $current) {
  83. $ts_result[$ts][$ol] = {
  84. time => $time,
  85. file => $_,
  86. };
  87. }
  88. }
  89. }
  90. },
  91. follow => $follow_symlinks,
  92. no_chdir => 1,
  93. },
  94. @$search_dirs
  95. );
  96. return \@ts_result;
  97. }
  98.  
  99.  
  100.  
  101. my $verbose = 0;
  102. my $show_gmt = 0;
  103. my $date_format;
  104. my $check_directory = 0;
  105. my $follow_symlinks = 0;
  106. my @ts_checklist;
  107. my @oldest_or_latest;
  108. do {
  109. my %ts_checklist;
  110. my %oldest_or_latest;
  111. my $needhelp;
  112. GetOptions(
  113. 'h|help' => \$needhelp,
  114. 'gmt' => sub { $show_gmt = 1 },
  115. 'f|date-format=s' => \$date_format,
  116. 'latest' => sub { $oldest_or_latest{$OL_LATEST} = 1 },
  117. 'oldest' => sub { $oldest_or_latest{$OL_OLDEST} = 1 },
  118. 'atime' => sub { $ts_checklist{$TS_ATIME} = 1 },
  119. 'mtime' => sub { $ts_checklist{$TS_MTIME} = 1 },
  120. 'ctime' => sub { $ts_checklist{$TS_CTIME} = 1 },
  121. 'd|directory' => \$check_directory,
  122. 'l|follow-symlinks' => \$follow_symlinks,
  123. 'v|verbose' => \$verbose,
  124. ) or usage;
  125. usage if $needhelp;
  126.  
  127. set_verbose $verbose;
  128.  
  129. @ts_checklist = keys %ts_checklist;
  130. unless (@ts_checklist) {
  131. say STDERR "error: choose any of --atime, --mtime, --ctime.";
  132. usage;
  133. }
  134. verbose '@ts_checklist = ' . uneval(\@ts_checklist);
  135.  
  136. @oldest_or_latest = keys %oldest_or_latest;
  137. unless (@oldest_or_latest) {
  138. say STDERR "error: choose any of --oldest, --latest.";
  139. usage;
  140. }
  141. verbose '@oldest_or_latest = ' . uneval(\@oldest_or_latest);
  142. };
  143.  
  144.  
  145. my @dirs = @ARGV ? @ARGV : (".");
  146. @dirs = grep {
  147. -d || do {
  148. say STDERR "warning: $_ is not a directory.";
  149. 0;
  150. };
  151. } @dirs;
  152.  
  153. my $ts_result = get_timestamps \@dirs, \@ts_checklist, \@oldest_or_latest, $check_directory, $follow_symlinks;
  154. for my $ts (@ts_checklist) {
  155. for my $ol (@oldest_or_latest) {
  156. # NOTE: If no files found, it does not say anything.
  157. next unless defined $ts_result->[$ts][$ol];
  158.  
  159. my $epoch = $ts_result->[$ts][$ol]{time};
  160. my $filename = $ts_result->[$ts][$ol]{file};
  161. my $time = $show_gmt ? gmtime($epoch) : localtime($epoch);
  162. my $str = defined $date_format ? $time->strftime($date_format) : "$time";
  163. say "$filename: $OL_NAME[$ol] $TS_NAME[$ts]: $str";
  164. }
  165. }
  166.  
  167. __END__
  168.  
  169. =head1 NAME
  170.  
  171. top-timestamp.pl - Get latest/oldest timestamp (atime, mtime, ctime)
  172.  
  173.  
  174. =head1 SYNOPSIS
  175.  
  176. $ perl top-timestamp.pl OPTIONS dir1 [dir2 ...]
  177.  
  178. =head1 OPTIONS
  179.  
  180. =over
  181.  
  182. =item -h, --help
  183.  
  184. Show this help.
  185.  
  186. =item --gmt
  187.  
  188. Show GMT.
  189.  
  190. =item -f, --date-format {format}
  191.  
  192. Specify date format to be output.
  193.  
  194. if specified, the result is the same
  195. as when POSIX's strftime() is used
  196. (top-timestamp.pl is using Time::Piece).
  197.  
  198. if not specified, the output string
  199. is the same as localtime() or gmitime() (string in scalar context).
  200.  
  201. =item --latest
  202.  
  203. Find and show latest timestamps.
  204. --atime, --mtime, --ctime to specify timestamps to find.
  205.  
  206. =item --oldest
  207.  
  208. Find and show oldest timestamps.
  209. --atime, --mtime, --ctime to specify timestamps to find.
  210.  
  211. =item --atime
  212.  
  213. Find and show atime.
  214.  
  215. =item --mtime
  216.  
  217. Find and show atime.
  218.  
  219. =item --ctime
  220.  
  221. Find and show atime.
  222.  
  223. =item -d, --directory
  224.  
  225. Check timestamps for also directories.
  226.  
  227. =item -l, --follow-symlinks
  228.  
  229. Follow symlinks.
  230.  
  231. =item -v, --verbose
  232.  
  233. For debug.
  234.  
  235. =back
  236.  
  237.  
  238. =head1 AUTHOR
  239.  
  240. tyru <tyru.exe@gmail.com>
Add Comment
Please, Sign In to add comment