2012-12-26 7 views
12

Ich habe ein Perl-Skript, das durch einen Ordner mit ein paar tausend Dateien geht.perl -f check kann Datei nicht identifizieren

Als ich das Drehbuch begann ich keine Kenntnis von der Perl-Datei war :: Funktionen finden, so, um alle Dateien in der Struktur zur Liste ich etwas entlang der Linie verwendet:

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

Nun aber Ich dachte, ich würde versuchen, dies von Perl zu tun, anstatt ein externes Programm zu starten. (Kein echter Grund, diese Änderung anders als wollen lernen, File :: Find zu verwenden.)

Versuchen, die Semantik von File :: Find Suche Funktion zu lernen Ich habe ein paar Dinge in der Befehlszeile ausprobiert und verglich die Ausgabe zu der von finden.

Seltsamerweise gibt es 1 Datei, die das Programm findet, aber die Perl-Funktion überspringt.

Suche funktioniert:

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

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 

ändern Ordner ausschließen, anstatt Dateien enthalten funktioniert:

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 

Der einzige Unterschied zwischen den Dateien ist die Größe:

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 auf der betreffenden Maschine ist alt, aber nicht alte:

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. 

Ist dies ein bekannter Fehler, oder was?

Oder treffe ich eine Größenbeschränkung von "-f"? Die Datei ist fast 4 GB und die größte in der Auswahl.

Oder ist mein Test (wenn -f) schlecht gewählt?

EDIT [versucht, Dateien stat]:

Big-Datei nicht

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

Kleine Datei arbeitet

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; 

Binary 'stat' auf beiden Dateien arbeitet

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 

auch:

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 "gelöst":

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

Neugierig. Können Sie [stat] (http://perldoc.perl.org/functions/stat.html) die Datei anzeigen und uns zeigen, was sie zurückgibt? –

+0

Der Status scheint ebenfalls zu versagen, ich werde den Beitrag bearbeiten und die Ergebnisse meiner Tests hinzufügen. – azzid

+1

Fehler? Wie in, gibt es eine leere Liste zurück? –

Antwort

10

Basis In a bit von Googling scheint es, dass Ihr Perl-Interpreter nicht mit large file support kompiliert wurde, wodurch stat (und alle Dateitests, die intern darauf beruhen, einschließlich -f) für Dateien größer als 2 GB fehlschlagen.

Um zu überprüfen, ob dies der Fall ist, führen Sie:

perl -V | grep "uselargefiles|FILE_OFFSET_BITS" 

Wenn Ihr Perl-Unterstützung für große Dateien hat, sollte die Ausgabe etwas wie uselargefiles=define und -D_FILE_OFFSET_BITS=64 zeigen. Ist dies nicht der Fall, ist es wahrscheinlich, dass Sie keine großen Dateien perl unterstützen.

Es mag etwas rätselhaft sein, warum große Dateien nur für stat Dateien benötigt werden. Das zugrunde liegende Problem ist, dass die 32-Bit-Version des stat(2) Systemaufruf, anstatt eine falsche Größe zurückkehrt, einfach mit EOVERFLOW nicht in eine Datei größer als 2 GB angewendet, wenn:

"EOVERFLOW

(stat()) Pfad zu einer Datei, deren Größe bezieht sich nicht in dem off_t Typ repräsentiert werden. Dies kann auftreten, wenn eine Anwendung ohneauf einer 32-Bit-Plattform kompiliert 210 -D_FILE_OFFSET_BITS = 64 ruft stat() für eine Datei auf, deren Größe (1 < < 31) -1 Bits überschreitet."

Technisch Erhalt diesen Fehlers sollte genug sein, um zu zeigen, dass die angegebene Datei vorhanden ist (obwohl ich denke, es ein wirklich gigantisches Verzeichnis sein könnte), aber Perl ist nicht intelligent genug, um zu erkennen, dass — es sieht nur, dass die Statistik nicht, und so gibt nichts

(Edit:. Wie ikegami in den Kommentaren richtig bemerkt, -f kehrt undef eher als 0 oder 1, wenn der stat (2) Aufruf fehlschlägt, und Sätze $! zum Fehlercode th verursacht den Fehler. Also, wenn es Ihnen nichts ausmacht anzunehmen, dass alle Verzeichniseinträge mit der Größe> 2GB Dateien sind, könnten Sie etwas wie -f $_ or (not defined -f _ and $!{EOVERFLOW}) machen, um danach zu suchen.)

+5

Es gibt nichts zurück; es gibt undef (Fehler) statt 0 (keine einfache Datei) zurück und setzt '$!' auf 'EOVERLFLOW'. Sie können nach einem Überlauf suchen, indem Sie '$! {EOVERFLOW}' überprüfen, wenn '-f' undef zurückgibt. – ikegami

+0

Sie, Sir, sind sehr korrekt. Sie können ein Bier einlösen, wann immer es für mich möglich ist zu liefern. ;) Vielen Dank! – azzid

+1

@azzid: Kein Problem. Wir können über das Bier sehen, wenn ich jemals einen Grund habe, in der Nähe von Linköping zu sein. :) –