12

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

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

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

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

为了学习 File::Find 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

编辑2

# 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
4

1 回答 1

10

根据一些歌搜索,您的 perl 解释器似乎没有使用大文件支持编译,导致stat(以及任何内部依赖它的文件测试,包括-f)对于大于 2GB 的文件失败。

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

perl -V | grep "uselargefiles|FILE_OFFSET_BITS"

如果您的 perl 支持大文件,则输出应显示类似于uselargefiles=defineand的内容-D_FILE_OFFSET_BITS=64。如果没有,很可能你的 perl 不支持大文件。

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

"溢出

( stat ()) path是指一个文件,其大小不能用off_t 类型表示。当在没有-D_FILE_OFFSET_BITS=64的 32 位平台上编译的应用程序在大小超过(1<<31)-1位的文件上调用stat () 时,可能会发生这种情况。”

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

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

于 2012-12-26T14:02:52.003 回答