[Dresden-pm] Nachfrage wegen rätselhaften Verhalten von Perl
A. Pagaltzis
pagaltzis at gmx.de
Son Jan 1 08:49:24 PST 2006
Hallo Hans-Dietrich,
* Hans-Dietrich Kirmse <hd.kirmse at gmx.de> [2006-01-01 16:00]:
> ich möchte alle Listenteilnehmern alle Gute für 2006 wünschen
Frohes Neues. :-)
> # kopiert den Inhalt eines Verzeichnisses in ein anderes
> sub copydir
> {
> my $quelle = shift;
> my $ziel = shift;
>
> my $recht = 0777;
>
> find (\&kopieren,$quelle);
>
> # ist sonst die Routine "wanted", was aber nichts zur Sache tut
> sub kopieren
Das funktioniert nie. Du hast hier eine benannte Closure; eine
solche wird an die lexikalischen Variablen des ersten Aufrufs
gebunden.
Du müsstest hier eigentlich Warnungen der Form
Variable "$quelle" will not stay shared at $script line $x.
Variable "$ziel" will not stay shared at $script line $y.
erhalten haben.
Das behebst du einfach, indem du stattdessen eine anonyme
Funktion verwendest.
> {
> my $reststring; # der Pfad zur Datei gekürzt um den Pfad zur Quelle
>
> # wenn es nicht das Ausgangsverzeichnis (die Quelle) ist
> if ($quelle ne $File::Find::name) {
> # dann holen wir uns den "Rest" des Dateinamens nach der Quelle
> if ($File::Find::name =~ /^$quelle(.*)$/) { $reststring = $1 };
Das ist umständlich und fehlerträchtig. Stattdessen solltest
einfach find() mit der Option no_chdir aufrufen und dann $_
verwenden.
> # wenn das gefundene Element ein Verzeichnis ist
> if (-d $File::Find::name) {
> # dann legen wir im Ziel ein neues Verzeichnis an
> mkdir($ziel.$reststring,$recht);
> } else {
> # dann kopieren wir diese Datei in dieses Ziel
> copy($File::Find::name,$ziel.$reststring);
Bitte immer File::Spec verwenden, um Pfade zusammenzubasteln.
> die Variable "$recht" soll in den Konfigurationsteil, […] gibt
> man die dann als Sting an oder wie macht man das korrekt?
Du willst ziemlich sicherlich die Rechte aus dem Quellbaum auf
den Zielbaum übertragen, nicht einen konstanten Wert verwenden;
und schon garnicht 777, es sei denn, die Sicherheit des Servers
ist dir piepe. :-)
Summa summarum:
use File::Find;
use File::Copy;
use File::Spec::Functions qw( abs2rel catfile canonpath );
use Fcntl qw( :mode );
sub copydir {
my ( $src, $dst ) = @_;
find( {
no_chdir => 1,
wanted => sub {
my $relsrc = abs2rel( $_, $src );
my $fulldst = canonpath( catfile( $dst, $relsrc ) );
my $srcmode = ( stat $_ )[ 2 ];
my $srcperm = S_IMODE( $srcmode );
if( S_ISDIR( $srcmode ) ) {
mkdir $fulldst, $srcperm;
}
else {
copy $_, $fulldst;
chmod $srcperm, $fulldst;
}
},
}, $src );
}
$relsrc ist hier der Pfad der zu bearbeitenden Datei aus $_
relativ zum Quellverzeichnis in $src. catfile() fügt diesen Pfad
ans Zielverzeichnis an; allerdings wird dabei aus dem obersten
Verzeichnis, »quelle/«, dabei »ziel/.« – das wird erst vermittels
canonpath() als »ziel« aufgelöst, ehe das Ergebnis in $fulldst
kommt.
In diesem Code fehlt allerdings ebenso wie auch in deinem
ursprünglichen jegliche Fehlerbehandlung.
Gruss,
--
#Aristoteles
*AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(",$\/"," ")[defined wantarray]/e;$1};
&Just->another->Perl->hacker;