Подтвердить что ты не робот

Perl -f проверить не удается определить файл

У меня есть perl script, который проходит через папку с несколькими тысячами файлов.

Когда я начал писать script, я не знал о perl File:: Find, поэтому, чтобы перечислить все файлы в структуре, я использовал что-то по строке:

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

Теперь, однако, я решил, что я попытаюсь сделать это из perl вместо запуска внешней программы. (Нет реальной причины для этого, кроме желания научиться использовать File:: Find.)

Попытка изучить семантику функции File:: Find find Я пробовал несколько вещей в командной строке и сравнивал вывод с результатами поиска.

Как ни странно, есть 1 файл, который находит find, но функция 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
4b9b3361

Ответ 1

На основе немного Googling, похоже, что ваш интерпретатор perl не был скомпилирован с поддержкой большого файла, вызывая stat (и любые проверки файлов, которые полагаются на него внутри, включая -f), чтобы сбой для файлов размером более 2 ГБ.

Чтобы проверить, так ли это, запустите:

perl -V | grep "uselargefiles|FILE_OFFSET_BITS"

Если ваш perl имеет большую поддержку файлов, вывод должен показывать что-то вроде uselargefiles=define и -D_FILE_OFFSET_BITS=64. Если это не так, вероятно, что вы perl не поддерживаете большие файлы.

Возможно, это несколько озадачивает, почему требуется большая поддержка файлов даже для файлов stat. Основная проблема заключается в том, что 32-разрядная версия системного вызова stat (2), а не возврат фиктивного размера, просто терпит неудачу с EOVERFLOW если применяется к файлу размером более 2 ГБ:

" EOVERFLOW

( stat()) путь относится к файлу, размер которого не может быть представлен в типе off_t. Это может произойти, когда приложение, скомпилированное на 32-битной платформе без -D_FILE_OFFSET_BITS = 64 вызывает stat() в файле, размер которого превышает (1 < 31) -1.

Технически, получение этой ошибки должно быть достаточным, чтобы указать, что именованный файл существует (хотя, я думаю, это может быть действительно очень удобный каталог), но perl недостаточно умен, чтобы понять, что — он просто видит, что stat потерпел неудачу, и поэтому ничего не возвращает.

(Edit: Поскольку ikegami правильно отмечает в комментариях, -f возвращает undef вместо 0 или 1, если вызов stat (2) завершается с ошибкой, и устанавливает $! в код ошибки, который вызвал сбой., если вы не возражаете, если все записи в каталоге с размером > 2 ГБ являются файлами, вы можете сделать что-то вроде -f $_ or (not defined -f _ and $!{EOVERFLOW}), чтобы проверить его.)