Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env perl
- use common::sense;
- use Getopt::Long qw(:config gnu_compat no_bundling no_ignore_case);
- use Pod::Usage;
- use File::Find;
- use Readonly;
- use Data::Dumper;
- use Time::Piece;
- # Constants for timestamps.
- Readonly::Scalar my $TS_ATIME => 0;
- Readonly::Scalar my $TS_MTIME => 1;
- Readonly::Scalar my $TS_CTIME => 2;
- Readonly::Scalar my $OL_OLDEST => 0;
- Readonly::Scalar my $OL_LATEST => 1;
- Readonly::Array my @TS_NAME => qw(
- atime
- mtime
- ctime
- );
- Readonly::Array my @OL_NAME => qw(
- oldest
- latest
- );
- Readonly::Array my @STAT_INDEX => (
- 8,
- 9,
- 10
- );
- sub usage () {
- print STDERR "\n\n";
- pod2usage(-verbose => 1, -output => \*STDERR);
- }
- sub uneval {
- local $Data::Dumper::Terse = 1;
- local $Data::Dumper::Indent = 1;
- Dumper(@_);
- }
- {
- my $verbose = 0;
- sub set_verbose {
- $verbose = shift;
- }
- sub verbose {
- $verbose and say STDERR "[verbose] ", @_;
- }
- }
- sub get_timestamps {
- my ($search_dirs, $ts_checklist, $oldest_or_latest, $check_directory, $follow_symlinks) = @_;
- my @ts_result = (undef) x 3;
- find(
- {
- wanted => sub {
- my @stat = stat $_;
- return if !$check_directory && -d _;
- verbose "processing $_...";
- for my $ts (@$ts_checklist) {
- for my $ol (@$oldest_or_latest) {
- my $time = $stat[$STAT_INDEX[$ts]];
- unless (defined $ts_result[$ts]) {
- $ts_result[$ts] = [({
- time => $time,
- file => $_,
- }) x 2];
- next;
- }
- my $current = $ts_result[$ts][$ol]{time};
- if ($ol == $OL_LATEST ? $time > $current : $time < $current) {
- $ts_result[$ts][$ol] = {
- time => $time,
- file => $_,
- };
- }
- }
- }
- },
- follow => $follow_symlinks,
- no_chdir => 1,
- },
- @$search_dirs
- );
- return \@ts_result;
- }
- my $verbose = 0;
- my $show_gmt = 0;
- my $date_format;
- my $check_directory = 0;
- my $follow_symlinks = 0;
- my @ts_checklist;
- my @oldest_or_latest;
- do {
- my %ts_checklist;
- my %oldest_or_latest;
- my $needhelp;
- GetOptions(
- 'h|help' => \$needhelp,
- 'gmt' => sub { $show_gmt = 1 },
- 'f|date-format=s' => \$date_format,
- 'latest' => sub { $oldest_or_latest{$OL_LATEST} = 1 },
- 'oldest' => sub { $oldest_or_latest{$OL_OLDEST} = 1 },
- 'atime' => sub { $ts_checklist{$TS_ATIME} = 1 },
- 'mtime' => sub { $ts_checklist{$TS_MTIME} = 1 },
- 'ctime' => sub { $ts_checklist{$TS_CTIME} = 1 },
- 'd|directory' => \$check_directory,
- 'l|follow-symlinks' => \$follow_symlinks,
- 'v|verbose' => \$verbose,
- ) or usage;
- usage if $needhelp;
- set_verbose $verbose;
- @ts_checklist = keys %ts_checklist;
- unless (@ts_checklist) {
- say STDERR "error: choose any of --atime, --mtime, --ctime.";
- usage;
- }
- verbose '@ts_checklist = ' . uneval(\@ts_checklist);
- @oldest_or_latest = keys %oldest_or_latest;
- unless (@oldest_or_latest) {
- say STDERR "error: choose any of --oldest, --latest.";
- usage;
- }
- verbose '@oldest_or_latest = ' . uneval(\@oldest_or_latest);
- };
- my @dirs = @ARGV ? @ARGV : (".");
- @dirs = grep {
- -d || do {
- say STDERR "warning: $_ is not a directory.";
- 0;
- };
- } @dirs;
- my $ts_result = get_timestamps \@dirs, \@ts_checklist, \@oldest_or_latest, $check_directory, $follow_symlinks;
- for my $ts (@ts_checklist) {
- for my $ol (@oldest_or_latest) {
- # NOTE: If no files found, it does not say anything.
- next unless defined $ts_result->[$ts][$ol];
- my $epoch = $ts_result->[$ts][$ol]{time};
- my $filename = $ts_result->[$ts][$ol]{file};
- my $time = $show_gmt ? gmtime($epoch) : localtime($epoch);
- my $str = defined $date_format ? $time->strftime($date_format) : "$time";
- say "$filename: $OL_NAME[$ol] $TS_NAME[$ts]: $str";
- }
- }
- __END__
- =head1 NAME
- top-timestamp.pl - Get latest/oldest timestamp (atime, mtime, ctime)
- =head1 SYNOPSIS
- $ perl top-timestamp.pl OPTIONS dir1 [dir2 ...]
- =head1 OPTIONS
- =over
- =item -h, --help
- Show this help.
- =item --gmt
- Show GMT.
- =item -f, --date-format {format}
- Specify date format to be output.
- if specified, the result is the same
- as when POSIX's strftime() is used
- (top-timestamp.pl is using Time::Piece).
- if not specified, the output string
- is the same as localtime() or gmitime() (string in scalar context).
- =item --latest
- Find and show latest timestamps.
- --atime, --mtime, --ctime to specify timestamps to find.
- =item --oldest
- Find and show oldest timestamps.
- --atime, --mtime, --ctime to specify timestamps to find.
- =item --atime
- Find and show atime.
- =item --mtime
- Find and show atime.
- =item --ctime
- Find and show atime.
- =item -d, --directory
- Check timestamps for also directories.
- =item -l, --follow-symlinks
- Follow symlinks.
- =item -v, --verbose
- For debug.
- =back
- =head1 AUTHOR
- tyru <tyru.exe@gmail.com>
Add Comment
Please, Sign In to add comment