【问题标题】:Find whether given files exist in a directory查找给定文件是否存在于目录中
【发布时间】:2019-02-24 09:25:03
【问题描述】:

我想知道给定目录中是否存在文件。

我需要在temporaryPath中找到某些.txt文件,但文件的目录需要适合模式,我需要知道文件是否存在于给定的模式中,因为我认为这是最快的方法找到文件,唯一的“不确定”或“.*”路径在 a/b/c/d/e/ 和 dou/you/1.txt 之间,如果我尝试在 a 下使用 Find::File 正常查找父目录 a/b/c/d/e/,大约需要 10 分钟,并且有可能我在数组中存储了不需要的路径,因为 1.txt 也存在于子目录中。

例如想要特定的目录

a/b/c/d/e/f/g/h/dou/you/1.txt
a/b/c/d/e/k/l/m/dou/you/1.txt

a/b/c/d/e/k/l/m/wanna/play/2.txt
a/b/c/d/e/z/x/c/wanna/play/2.txt

a/b/c/d/e/f/g/h/with/me/3.txt
a/b/c/d/e/z/x/c/with/me/3.txt

Perl

use strict;
use warnings;

my @temporaryPath = qw(
    dou/you/1.txt
    wanna/play/2.txt
    with/me/3.txt
    like/play/4.txt
    anything/really/5.txt
);

foreach my $temporaryList ( @temporaryPath ) {

    my $dir = "a/b/c/d/e/" . "*" . "/$temporaryList";

    if ( -e $dir ) {
        print " exist :) $temporaryList\n";
    }
    else {
        print " not exist :( $temporaryList\n";
    }
}

我在$dir中使用了.*,因为路径完整路径之间有很多不同的目录 ,例如f/g/hk/l/mz/x/c

结果是这样的

not exist :( dou/you/1.txt
not exist :( wanna/play/2.txt
not exist :( with/me/3.txt
not exist :( like/play/4.txt
not exist :( anything/really/5.txt

意思是$dir无法读取a/b/c/d/e/.*/

有什么办法吗?

【问题讨论】:

  • 听起来您想查看特定文件是否位于目录树中的某个位置,但不知道它们的确切路径?如果是这样,File::Find 就是你的朋友。
  • @Shawn,我知道目录在哪里,我只想知道它是否可以在路径中间使用 .* 以及为什么我不能在 $dir 中声明我的路径。如果我使用Find::File,它将在父目录的子目录中搜索所有需要的文件,并且这些文件在子目录中具有相同的名称。
  • 好的。 -e 和其他所有采用文件名的东西都需要文件的相对或绝对路径。没有像 shell 这样的通配符会扩展。
  • @Shawn,如果我想在这个父目录中找到我想要的文件 a/b/c/d/e/ ,所花费的时间是如此之长。例如,我的@files123 = File::Find::Rule->file() ->name( '1.txt' ) ->in( 'a/b/c/d/e/' );并且存在风险,即我获得了我不想要的目录路径。我希望文件必须在这个父文件夹 a/b/c/d/e/ 和这个文件夹中 dou/you/1.txt ,完整路径应该是 a/b/c/d/e/f/g /h/dou/you/1.txt 或 a/b/c/d/e/k/l/m/dou/you/1.txt 或 a/b/c/d/e/z/x/c /dou/you/1.txt ,文件 1.txt 必须在这些完整路径之一中。
  • 也许您可以edit 提出您的问题,并包含一组示例目录和文件,并说明您想找到哪些和不想找到哪些。

标签: perl directory file-exists


【解决方案1】:

-e 正确报告没有路径为a/b/c/d/e/*/dou/you/1.txt 的文件,因为a/b/c/d/e 中没有名为* 的目录。

use File::Find::Rule qw( );

my @targets = qw(
    dou/you/1.txt
    wanna/play/2.txt
    with/me/3.txt
    like/play/4.txt
    anything/really/5.txt
);

my $base_dir_qfn = 'a/b/c/d/e';

my @files = File::Find::Rule->file->in($base_dir_qfn);

my $target_pat = join '|', map quotemeta, @targets;
my $target_re = qr{/(?:$target_pat)\z};

for my $file (@files) {
   say $file if $file =~ $target_re;
}

测试:

$ mkdir -p a/b/c/d/e/f/g/h/dou/you;    touch a/b/c/d/e/f/g/h/dou/you/1.txt
$ mkdir -p a/b/c/d/e/k/l/m/dou/you;    touch a/b/c/d/e/k/l/m/dou/you/1.txt
$ mkdir -p a/b/c/d/e/k/l/m/wanna/play; touch a/b/c/d/e/k/l/m/wanna/play/2.txt
$ mkdir -p a/b/c/d/e/z/x/c/wanna/play; touch a/b/c/d/e/z/x/c/wanna/play/2.txt
$ mkdir -p a/b/c/d/e/f/g/h/with/me;    touch a/b/c/d/e/f/g/h/with/me/3.txt
$ mkdir -p a/b/c/d/e/z/x/c/with/me;    touch a/b/c/d/e/z/x/c/with/me/3.txt
$ perl a.pl
a/b/c/d/e/f/g/h/dou/you/1.txt
a/b/c/d/e/f/g/h/with/me/3.txt
a/b/c/d/e/k/l/m/dou/you/1.txt
a/b/c/d/e/k/l/m/wanna/play/2.txt
a/b/c/d/e/z/x/c/wanna/play/2.txt
a/b/c/d/e/z/x/c/with/me/3.txt

【讨论】:

  • 嘿@ikegami,谢谢你的解决方案,想解释一下吗?my $target_pat = join '|', map quotemeta, @targets;我的 $target_re = qr{/(?:$target_pat)\z};
  • 我尝试使用上面的脚本运行,但奇怪的是它不会搜索所有文件夹,例如它只通过“a/b/c/d/e/k/l/m /$temporaryList" 当我说 $file if not $file =~ $target_re; ,据说它也必须通过“a/b/c/d/e/z/x/c/$temporaryList”搜索,因为该文件只存在于f/g/h目录中,为什么当我打印出来时,它只搜索仅针对某些文件夹,请注意,我有数百个目录,f/g/hk/l/m 和 z/x/c 等目录只是示例。
  • 它构建了一个正则表达式模式。打印$target_re 看看。
  • 搜索a/b/c/d/e的每个子文件夹。与您的说法相反,它找到a/b/c/d/e/z/x/c/dou/you/1.txt
  • 我还是找不到文件。尝试了不同的目录,它仍然没有搜索 a/b/c/d/e/f/ 和 a/b/c/d/e/k/,它只搜索每个目录的 1 个目录,比如说,那里这是目录 a/b/c/d/e/f/ , a/b/c/d/e/z/ , a/b/c/d/e/k/ 和 a/b/c/d/ e/v/ 在第一个父目录下,在 a/b/c/d/e/f/ 的子目录下,有 a/b/c/d/e/f/g , a/b/c/ d/e/f/q , a/b/c/d/e/f/w,每层只搜索 1 个目录。
【解决方案2】:

听起来你需要 File::Globstar 模块。它实现了等效于 shell globstar 扩展,这将允许模式中的两个星号 ** 匹配任何字符串,包括路径分隔符

可能是这样的

use strict;
use warnings 'all';
use feature 'say';

use File::Globstar 'globstar';

my @paths = qw{
    dou/you/1.txt
    wanna/play/2.txt
    with/me/3.txt
    like/play/4.txt
    anything/really/5.txt
};

for my $path ( @paths ) {

    say for globstar "a/b/c/d/e/**/$path;
}

【讨论】:

  • 我尝试下载 File::Globstar 并使用 lib 'somepath' ,但出现了这个问题,“dpgettext”不是由 Locale::Messages 模块导出的,“dnpgettext”不是由Locale::Messages 模块,我用谷歌搜索了它,但没有找到解决方案。 @鲍罗丁
  • 听起来你的 Locale::Messages 版本可能已经过时了。在您的终端上运行 perl -MLocale::Messages\ 99 并告诉我们它显示的是哪个版本号。最新的是 1.29。但是,这不太可能,因为 it was added in 2008 如果我正确阅读了 github 发布页面,那么它一定是在 1.17 中加入的。
  • @simbabque ,我尝试运行,但找不到它,因为我使用 , 使用 lib"",将 globstar 模块存储在我的下载文件夹中,我无法将其添加到 Perl 目录,有限制。
  • @DanialHaris 在命令中添加 -I=<your lib directory> 标志(大写 i)以添加额外的 lib
  • @Danial:计算机程序可能很难描述,您需要尽可能明确。 Stack Overflow 提供 Markdown 来格式化你的帖子,你应该最大限度地使用它来清楚地解释自己。有一个很好的帮助页面Markdown Editing Help,你应该学习和应用它。
猜你喜欢
  • 1970-01-01
  • 2012-06-28
  • 2016-02-01
  • 2010-11-08
  • 2017-12-16
  • 2012-03-19
  • 1970-01-01
  • 2010-12-13
  • 2012-05-01
相关资源
最近更新 更多