Find up-to-date files for different paths but with identical file names

末鹿安然 提交于 2020-01-06 15:29:06

问题


I have the following files

./path/to/stuff1/file1    (x)
./path/to/stuff1/file2
./path/to/stuff1/file3

./path/to/stuff2/file1
./path/to/stuff2/file2    (x)
./path/to/stuff2/file3

./path/to/stuff3/file1    (x)
./path/to/stuff3/file2
./path/to/stuff3/file3

where I marked the files I touched lastly. I want to get exactly those marked files. In other words:

  • I want to get the up-to-date file for each directory.

I constructed the bash command

for line in $( find . -name 'file*' -type f | awk -F/ 'sub($NF,x)' | sort | uniq ); do
        find $line -name 'file*' -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2 -d' '
done

which I am able to use in perl using the system command and escaping the $. Is it possible to do this directly in perl or do you think my approach is fine?

edit

If possible the task should be done in perl without using external modules.

edit2

Sorry, I noticed my question wasn't clear. I thought the answer of @TLP would work but I have to clearify: I want to check for the newest file in each folder, e.g. the newest file in stuff1. Say I do

touch ./path/to/stuff1/file1
touch ./path/to/stuff2/file2
touch ./path/to/stuff3/file1

before I run the script. It then should output:

./path/to/stuff1/file1
./path/to/stuff2/file2
./path/to/stuff3/file1

The filename can be identical for different stuff but only one file per path should be output.

The script of @codnodder does this but I wish to search for only for the filename and not for the full path. So I want to search for all files beginning with file and the script should search recursively.


回答1:


Your find command can be emulated with File::Find's find command. This is a core module in Perl 5, and is almost certainly already on your system. To check the file modification time, you can use the -M file test.

So something like this:

use strict;
use warnings;
use File::Find;

my %times;
find(\&wanted, '.');
for my $dir (keys %times) {
    print $times{$dir}{file}, "\n";
}

sub wanted {
    return unless (-f && /^file/);
    my $mod = -M $_;
    if (!defined($times{$File::Find::dir}) or
        $mod < $times{$File::Find::dir}{mod}) {
        $times{$File::Find::dir}{mod} = $mod;
        $times{$File::Find::dir}{file} = $File::Find::name;
    }
}

If I run this command in my test directory, on my system, I get the following Data::Dumper structure, where you can clearly see the file name key, the full path stored in the file key, and the modification date (in days compared to the run time of the script) as the mod.

$VAR1 = {
          './phone' => {
                         'file' => './phone/file.txt',
                         'mod' => '3.47222222222222e-005'
                       },
          './foo' => {
                       'file' => './foo/fileb.txt',
                       'mod' => '0.185'
                     },
          '.' => {
                   'file' => './file.conf',
                   'mod' => '0.154490740740741'
                 }
        };



回答2:


There are 3 general approaches I can think of.

  1. Using opendir(), readdir(), and stat().
  2. using File::Find.
  3. Using glob().

The most appropriate option depends on the specifics of what you have to work with, that we can't see from your posting.

Also, I assume when you say "no external modules", you are not excluding modules installed with Perl (i.e., in Core).

Here is an example using glob():

use File::Basename qw/fileparse/;

for my $file (newest_file()) {
    print "$file\n";
}

sub newest_file {
    my %files;
    for my $file (glob('./path/stuff*/file*')) {
        my ($name, $path, $suffix) = fileparse($file);
        my $mtime = (stat($file))[9];
        if (!exists $files{$path} || $mtime > $files{$path}[0]) {
            $files{$path} = [$mtime, $name];
        }
    }
    return map { $files{$_}[1] } keys %files;
}


来源:https://stackoverflow.com/questions/20540967/find-up-to-date-files-for-different-paths-but-with-identical-file-names

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!