2012-12-26 15 views
12

Mam skrypt perla, który przechodzi przez folder z kilkoma tysiącami plików.perl -f check nie rozpoznaje pliku

Kiedy zacząłem pisać scenariusz byłem nieświadomy perl File :: Znajdź funkcje, tak aby wyświetlić listę wszystkich plików w strukturze kiedyś coś wzdłuż linii:

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

Teraz jednak Pomyślałem, że spróbuję zrobić to z perla, zamiast uruchamiać zewnętrzny program. (Nie ma prawdziwego powodu, aby zrobić tę zmianę, poza tym, że chce się nauczyć używać File :: Find.)

Próba opanowania semantyki funkcji File :: Find find Próbowałem kilku rzeczy w linii poleceń i porównałem wyjście do znalezienia.

Co dziwne, znajduje się 1 plik znaleziony przez program, ale funkcja perl przeskakuje.

Wyszukiwanie działa:

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 nie:

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 

Zmiana wykluczyć foldery zamiast zawierać pliki działa:

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 

Jedyna różnica między plikami jest rozmiar:

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 na maszynie w pytaniu jest stary, ale nie starożytny:

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. 

Jest to znany błąd lub coś?

Czy przekraczam limit rozmiaru "-f"? Plik ma prawie 4 GB i jest największy w wyborze.

Czy mój test (jeśli -f) jest źle wybrany?

EDIT [próbuje stat pliki]:

Big plik nie

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

mały plik działa

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; 

binarny 'stat' działa na obu plików

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 

również:

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 

problem "rozwiązany":

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 

Works:

# 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 
+1

Ciekawy. Czy możesz [stat] (http://perldoc.perl.org/functions/stat.html) plik i pokazać nam, co zwraca? –

+0

Statystyki wydają się nie działać, będę edytować post i dodać wyniki moich testów. – azzid

+1

Fail? Jak w, zwraca pustą listę? –

Odpowiedz

10

bazowa d na a bit z Googling, wygląda Twój perl interpreter nie został skompilowany z large file support, powodując (testy i żadnych plików, które opierają się na nim wewnętrznie, w tym -f) stat niepowodzenie dla plików większych niż 2 GB.

Aby sprawdzić, czy jest to przypadek, uruchom:

perl -V | grep "uselargefiles|FILE_OFFSET_BITS" 

Jeśli Perl posiada obsługę dużych plików, wyjście powinno pokazać coś podobnego uselargefiles=define i -D_FILE_OFFSET_BITS=64. Jeśli nie, prawdopodobnie perl nie obsługuje dużych plików.

Może być nieco zastanawiające, dlaczego potrzebna jest duża obsługa plików, nawet dla plików tylko stat. Podstawowym problemem jest to, że wersja 32-bitowa wywołania systemowego stat(2) zamiast przekazujących fałszywe wielkości, po prostu nie z EOVERFLOW jeżeli są stosowane do pliku większego niż 2 GB:

"EOVERFLOW

(stat()) ścieżka odnosi się do pliku, którego wielkość nie może być przedstawiony w figurze off_t. może to mieć miejsce gdy aplikacja zestawiane na platformie 32-bitowego, bez -D_FILE_OFFSET_BITS = 64 połączenia STAT() w pliku, którego rozmiar przekracza (1 < < 31) -1 bitów."

Technicznie otrzymaniu tego błędu powinny wystarczy wskazać, że dany plik nie istnieje (choć myślę, że może to być katalog naprawdę humongous też), ale Perl nie jest wystarczająco silny, aby uświadomić sobie, że — po prostu widzi, że stat nie, i tak nic nie zwraca

(Edit. Jak Ikegami słusznie zauważa w komentarzach, -f powraca undef zamiast 0 lub 1, jeśli stat (2) połączenia nie powiedzie się, a zestawy $! do kodu błędu th w wyniku awarii. Tak więc, jeśli nie masz nic przeciwko założeniu, że wszystkie pozycje katalogu o rozmiarze> 2 GB są plikami, możesz zrobić coś takiego, jak -f $_ or (not defined -f _ and $!{EOVERFLOW}), aby to sprawdzić.)

+5

Nic nie zwraca; zwraca undef (błąd) zamiast 0 (nie zwykły plik) i ustawia '$!' na 'EOVERLFLOW'. Możesz sprawdzić przepełnienie, zaznaczając '$! {EOVERFLOW}', gdy '-f' zwraca undef. – ikegami

+0

Ty, panie, masz rację. Możesz spieniężyć piwo, gdy tylko będę mógł je dostarczyć. ;) Dziękuję Ci! – azzid

+1

@azzid: Nie ma problemu. Możemy zobaczyć piwo, jeśli kiedykolwiek będę miał jakiś powód, by być blisko Linköping. :) –

Powiązane problemy