【问题标题】:perl -f check fails to identify fileperl -f 检查无法识别文件
【发布时间】:2012-12-11 23:45:30
【问题描述】:

我有一个 perl 脚本,它通过一个包含几千个文件的文件夹。

当我开始编写脚本时,我不知道 perl File::Find 函数,所以为了列出结构中的所有文件,我使用了以下内容:

open (FILES, "$FIND $FOLDER -type f |");
while (my $line = <FILES>) {...}

现在我想我会尝试从 perl 中执行此操作,而不是启动外部程序。 (除了想学习使用 File::Find 之外,没有真正的理由进行此更改。)

尝试学习 File::Find find 函数的语义 我在命令行上尝试了一些东西,并将输出与 find 的输出进行了比较。

奇怪的是,程序找到了 1 个文件,但 perl 函数跳过了。

寻找作品:

machine:~# find /search/path -type f | grep UNIQ
/search/path/folder/folder/UNIQ/movie_file_015.MOV
/search/path/folder/folder/UNIQ/movie_file_145.MOV
/search/path/folder/folder/UNIQ/Thumbs.db

machine:~# find /search/path -type f | wc -l
    6439

Perl 失败:

machine:~# perl -e 'use File::Find; find(sub { print $File::Find::name . "\n" if -f }, "/search/path");' | grep  UNIQ
/search/path/folder/folder/UNIQ/movie_file_145.MOV
/search/path/folder/folder/UNIQ/Thumbs.db

machine:~# perl -e 'use File::Find; find(sub { print $File::Find::name . "\n" if -f }, "/search/path");' | wc -l
    6438

更改为排除文件夹而不是包含文件有效:

machine:~# perl -e 'use File::Find; find(sub { print $File::Find::name . "\n" unless -d }, "/search/path");' | grep  UNIQ
/search/path/folder/folder/UNIQ/movie_file_015.MOV
/search/path/folder/folder/UNIQ/movie_file_145.MOV
/search/path/folder/folder/UNIQ/Thumbs.db

文件之间的唯一区别是大小:

machine:~# ls -l /search/path/folder/folder/UNIQ/
total 4213008
-rw-rw-r--    1 user users    4171336632 May 27  2012 movie_file_015.MOV
-rw-rw-r--    1 user users    141610616 May 27  2012 movie_file_145.MOV
-rw-rw-r--    1 user users       20992 May 27  2012 Thumbs.db

有问题的机器上的 Perl 是旧的但不是古老的:

machine:~# perl -version

This is perl, v5.8.8 built for sparc-linux

Copyright 1987-2006, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

这是一个已知的错误还是什么?

或者我是否达到了“-f”的一些大小限制?该文件将近 4GB,是所选文件中最大的。

或者我的测试(如果 -f)选择不当?

编辑 [尝试统计文件]:

大文件失败

machine:~# perl -e 'use Data::Dumper; print Dumper(stat("/search/path/folder/folder/UNIQ/movie_file_015.MOV"));'

小文件作品

machine:~# perl -e 'use Data::Dumper; print Dumper(stat("/search/path/folder/folder/UNIQ/movie_file_145.MOV"));'
$VAR1 = 65024;
$VAR2 = 19989500;
$VAR3 = 33204;
$VAR4 = 1;
$VAR5 = 1004;
$VAR6 = 100;
$VAR7 = 0;
$VAR8 = 141610616;
$VAR9 = 1349281585;
$VAR10 = 1338096718;
$VAR11 = 1352403842;
$VAR12 = 16384;
$VAR13 = 276736;

二进制“stat”适用于两个文件

machine:~# stat /search/path/folder/folder/UNIQ/movie_file_015.MOV
  File: "/search/path/folder/folder/UNIQ/movie_file_015.MOV"
  Size: 4171336632  Blocks: 8149216    IO Block: 16384  Regular File
Device: fe00h/65024d        Inode: 19989499    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1004/user)   Gid: (  100/   users)
Access: 2012-10-03 18:11:05.000000000 +0200
Modify: 2012-05-27 07:23:34.000000000 +0200
Change: 2012-11-08 20:44:02.000000000 +0100

machine:~# stat /search/path/folder/folder/UNIQ/movie_file_145.MOV
  File: "/search/path/folder/folder/UNIQ/movie_file_145.MOV"
  Size: 141610616   Blocks: 276736     IO Block: 16384  Regular File
Device: fe00h/65024d        Inode: 19989500    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1004/user)   Gid: (  100/   users)
Access: 2012-10-03 18:26:25.000000000 +0200
Modify: 2012-05-27 07:31:58.000000000 +0200
Change: 2012-11-08 20:44:02.000000000 +0100

还有:

machine:~# perl -e 'stat("/search/path/folder/folder/UNIQ/movie_file_145.MOV"); print $! . "\n";'
Bad file descriptor

machine:~# perl -e 'stat("/search/path/folder/folder/UNIQ/movie_file_015.MOV"); print $! . "\n";'
Value too large for defined data type

EDIT2

# perl -V | grep "uselargefiles|FILE_OFFSET_BITS"
config_args='-Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=sparc-linux -Dprefix=/usr -Dprivlib=/usr/share/perl/5.8 -Darchlib=/usr/lib/perl/5.8 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.8.8 -Dsitearch=/usr/local/lib/perl/5.8.8 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Dstatic_ext=B ByteLoader GDBM_File POSIX re -Dusemymalloc -Uuselargefiles -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dlibperl=libperl.so.5.8.8 -Dd_dosuid -des'
useperlio=define d_sfio=undef uselargefiles=undef usesocks=undef

问题“已解决”:

machine:~# perl -e 'stat("/search/path/folder/folder/UNIQ/movie_file_015.MOV"); print $!{EOVERFLOW} . "\n";'
92
machine:~# perl -e 'stat("/search/path/folder/folder/UNIQ/movie_file_145.MOV"); print $!{EOVERFLOW} . "\n";'
0

作品:

# perl -e 'use File::Find; find(sub { print $File::Find::name . "\n" if -f or ( $!{EOVERFLOW} > 0 and not -d) }, "/search/path");' | grep UNIQ
/search/path/folder/folder/UNIQ/movie_file_015.MOV 
/search/path/folder/folder/UNIQ/movie_file_145.MOV 
/search/path/folder/folder/UNIQ/Thumbs.db

【问题讨论】:

  • 很好奇。你能stat该文件并向我们展示它返回的内容吗?
  • 统计数据似乎也失败了,我将编辑帖子并添加我的测试结果。
  • 失败?如,它返回一个空列表??
  • 是的,麻烦的文件得到了空列表。同一文件夹中较小的文件使用相同的调用获得一堆数据。
  • 统计失败后$!是什么?

标签: perl file


【解决方案1】:

基于Googlinga bit,您的perl 解释器似乎没有使用large file support 编译,导致stat(以及任何内部依赖它的文件测试,包括-f)失败对于大于 2GB 的文件。

要检查是否是这种情况,请运行:

perl -V | grep "uselargefiles|FILE_OFFSET_BITS"

如果您的 perl 支持大文件,则输出应显示类似 uselargefiles=define-D_FILE_OFFSET_BITS=64 的内容。如果不支持,可能是您的 perl 不支持大文件。

这可能有点令人费解,为什么即使只是stating 文件也需要大文件支持。根本问题在于,如果应用于大于 2GB 的文件,stat(2) 系统调用的 32 位版本并没有返回虚假大小,而是简单地以 EOVERFLOW 失败:

"EOVERFLOW

(stat()) path 指的是一个文件,其大小不能用 off_t 类型表示。当在没有 -D_FILE_OFFSET_BITS=64 的 32 位平台上编译的应用程序对大小超过 (1 位。”

从技术上讲,收到该错误应该足以表明命名文件确实存在(尽管我猜它也可能是一个真正巨大的目录),但 perl 还不够聪明,无法意识到——它只是看到 stat 失败,因此什么也不返回。

(编辑: 正如 ikegami 在 cmets 中正确指出的那样,如果 stat(2) 调用失败,-f 返回 undef 而不是 0 或 1,并将 $! 设置为错误导致失败的代码。因此,如果您不介意假设所有大小 > 2GB 的目录条目都是文件,您可以执行类似-f $_ or (not defined -f _ and $!{EOVERFLOW}) 的操作来检查它。)

【讨论】:

  • 它什么也不返回;它返回undef(错误)而不是0(不是普通文件)并将$!设置为EOVERLFLOW。当-f 返回 undef 时,您可以通过检查$!{EOVERFLOW} 来检查溢出。
  • 您,先生,非常正确。只要我可以送货,您就可以兑现啤酒。 ;) 谢谢!
  • @azzid:没问题。如果我碰巧有理由在林雪平附近,我们可以了解一下啤酒。 :)
  • Perl 无法知道命名条目是一个文件,因为 stat 失败,所以它没有执行该测试的模式位。它知道名称存在,但不知道它是普通文件、目录还是什么......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-15
  • 1970-01-01
  • 2021-11-01
  • 1970-01-01
  • 2012-01-01
  • 2021-02-11
相关资源
最近更新 更多