Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]7693[/thread]

rekursion klappt nicht

Leser: 1


<< >> 10 Einträge, 1 Seite
supersucker
 2006-02-09 21:07
#62814 #62814
User since
2005-03-17
118 Artikel
BenutzerIn
[default_avatar]
hi,

da mein k3b gelegentlich trotz korrekter joliet-einstellungen beim brennen von mp3 mit nicht brennfreundlichen namen abschmiert und ich demnächst auf arbeit auch wieder perl programmieren muss, dachte ich mir meine verstaubten perl-kenntnisse wieder aufzufrischen in dem ich mir ein script schreibe das rekursiv alle verzeichnisse durchgeht und audio-dateien einen brennfreundlichen, im sinne von keine sonderzeichen und keine überlänge, dateinamen vergibt.

leider gibt mir mein erster versuch einen fehler mit dem ich nicht wirklich weiter komme.

das script:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/perl

use strict;
use warnings;

#####################################################################
#
#
# script which scans recursively all folders based on #
# the current directory and renames audio file-names #
# to a burn-friendly format
#
#

#
#####################################################################


# constants &nb
sp; #

use constant MAX_FILENAME_LENGTH => 31;

# main script
#

print "start renaming files....\n";

scanDir();

print "finished renaming files....\n";

# functions &nb
sp; #

sub scanDir {

# open current directory

opendir(CURDIR, ".") or die "could not open directory! \n";

# iterate over directory entries

while(my $dirEntry = <CURDIR>) {

# skip "." and ".."

if($dirEntry eq "." || $dirEntry eq "..") {
next;
}

# if we encounter a audio-file

if(-f $dirEntry && $dirEntry =~ m/(.*mp3$)|(.*ogg$)/) {
renFile($dirEntry);
}

# if we encounter a directory, descend into it and start recursion

elsif(-d $dirEntry) {
chdir($dirEntry) or die "could not open directory $dirEntry! \n";
scanDir();
}

}
return 0;
}



sub renFile {


my $newFileName = my $oldFileName = shift;

# delete all special chars

$newFileName =~ s/[^a-zA-Z0-9_\,-]//;

# shorten file name if necessary and rebuild filename

$newFileName = substr($newFileName, 0, MAX_FILENAME_LENGTH) . substr($oldFileName, -4)
if(length($newFileName) > MAX_FILENAME_LENGTH);

rename ($oldFileName, $newFileName) or die "could not rename file $oldFileName !\n";

return 0;
}


führe ich das in der shell aus krieg ich:

Code: (dl )
1
2
3
4
5
 ./rectFileNames.pl
start renaming files....
readline() on unopened filehandle CURDIR at ./rectFileNames.pl line 37.
(Are you trying to call readline() on dirhandle CURDIR?)
finished renaming files....


kann mit dieser fehlermeldung jemand was anfangen?

hab ich hier irgendwas offensichtliches übersehen?

hoffe ihr könnt mir helfen!

ps: ich weiss das es für sowas genügend module gibt die rekursiv verzeichnisse durchgehen, würde es aber halt interessehalber gerne selber machen

pps: hmmpf, war ja klar das mir forum wieder meine formatierung zerhaut.......\n\n

<!--EDIT|supersucker|1139512449-->
murphy
 2006-02-09 23:27
#62815 #62815
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Datei- und Verzeichnishandles haben globalen Gültigkeitsbereich. Du solltest statt
Code: (dl )
opendir(CURDIR, ".") or die "could not open directory! \n";
entweder
Code: (dl )
1
2
local *CURDIR;
opendir(CURDIR, '.') or die "could not open directory: $!\n";
oder
Code: (dl )
opendir(my $curdir, '.') or die "could not open directory: $!\n";
verwenden.

Im letzteren Fall musst du dann natürlich auch im Rest der Verzeichnislesefunktion die lexikalische Variable $curdir statt des Verzeichnishandles CURDIR verwenden.
When C++ is your hammer, every problem looks like your thumb.
renee
 2006-02-10 00:33
#62816 #62816
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Warum verwendest Du eigentlich nicht CPAN:File::Find??
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
supersucker
 2006-02-10 16:47
#62817 #62817
User since
2005-03-17
118 Artikel
BenutzerIn
[default_avatar]
Quote
Warum verwendest Du eigentlich nicht CPAN: File::Find


siehe eröffnung:

Quote
ps: ich weiss das es für sowas genügend module gibt die rekursiv verzeichnisse durchgehen, würde es aber halt interessehalber gerne selber machen


@murphy:

danke für den hinweis, ich habe jetzt das script nach deinem ersten vorschlag umgeschrieben, leider klappt es immer noch nicht..

die funktion sieht jetzt so aus:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
sub scanDir {

print "scandir() aufgerufen! \n";

# open current directory

local *CURDIR;
opendir(CURDIR, ".") or die "could not open directory $! \n";

# iterate over directory entries

while(my $dirEntry = <CURDIR>) {

# skip "." and ".."

if($dirEntry eq "." || $dirEntry eq "..") {
print "skipping . and ..! \n";
next;
}

# if we encounter a audio-file

if(-f $dirEntry && $dirEntry =~ m/(.*mp3$)|(.*ogg$)/) {
print "renaming file! \n";
renFile($dirEntry);
}

# if we encounter a directory, descend into it and start recursion

elsif(-d $dirEntry) {
chdir($dirEntry) or die "could not open directory $dirEntry! \n";
print "descend into next directory! \n";
scanDir();
}

}

close(CURDIR);

return 0;
}


da krieg ich nun eine merkwürdige (zumindest für mich) fehlermeldung:

Quote
./rectFileNames.pl
start renaming files....
scandir() aufgerufen!
readline() on unopened filehandle CURDIR at ./rectFileNames.pl line 40.
(Are you trying to call readline() on dirhandle CURDIR?)
finished renaming files....


hmm,

damit kann ich überhaupt nichts anfangen, erstens verwende ich readline ja nicht und zweitens öffne ich doch das filehandle.

deinen zweiten vorschlag:

Code: (dl )
opendir(my $curdir, '.') or die "could not open directory: $!\n";


konnte ich nicht verwenden, da ich nicht weiss wie ich darüber iteriere (mit anderen worten, was ich dann in die bedingung der while-schleife schreiben), $curdir wäre doch dann ein skalar, oder?
vayu
 2006-02-10 17:35
#62818 #62818
User since
2005-01-13
782 Artikel
BenutzerIn
[default_avatar]
du könntest auch folgendes machen:

Code (perl): (dl )
1
2
3
4
5
6
7
8
opendir(DIR, '.') or die $!;

my @dir = readdir(DIR);
closedir DIR;

foreach(@dir) {
    ...
}


könnte zwar ein speicherfresser werden, (je nachdem wie gross deine verzeichnissstruktur ist) aber so hats bei mir gut funktioniert.

ansonsten wäre es noch von vorteil, wenn du evlt mal die Zeile 40 markierst, damit wir sehen können wo der fehler flegt.\n\n

<!--EDIT|vayu|1139585816-->
supersucker
 2006-02-10 18:27
#62819 #62819
User since
2005-03-17
118 Artikel
BenutzerIn
[default_avatar]
Quote
nsonsten wäre es noch von vorteil, wenn du evlt mal die Zeile 40 markierst, damit wir sehen können wo der fehler flegt.


sorry, zeile 40 ist:

Code: (dl )
    while(my $dirEntry = <CURDIR>) 


hmm, aber ich sehe einfach nix was falsch aussieht....
murphy
 2006-02-10 18:29
#62820 #62820
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
[quote=supersucker,10.02.2006, 14:47]@murphy:
[...]
da krieg ich nun eine merkwürdige (zumindest für mich) fehlermeldung:

Quote
./rectFileNames.pl
start renaming files....
scandir() aufgerufen!
readline() on unopened filehandle CURDIR at ./rectFileNames.pl line 40.
       (Are you trying to call readline() on dirhandle CURDIR?)
finished renaming files....


hmm,

damit kann ich überhaupt nichts anfangen, erstens verwende ich readline ja nicht und zweitens öffne ich doch das filehandle.

deinen zweiten vorschlag:

Code: (dl )
opendir(my $curdir, '.') or die "could not open directory: $!\n";


konnte ich nicht verwenden, da ich nicht weiss wie ich darüber iteriere (mit anderen worten, was ich dann in die bedingung der while-schleife schreiben),  $curdir wäre doch dann ein skalar, oder?[/quote]
Zu der Fehlermeldung: Du verwendest durchaus readline, denn der Ausdruck
Code: (dl )
<CURDIR>
ist nur eine praktische Abkürzung für den Ausdruck
Code: (dl )
readline(*CURDIR)
. Genau da liegt auch das Problem, denn ein Verzeichnishandle kann nicht mit readline ausgelesen werden. Du musst stattdessen, wie es vayu in seinem Beispiel schreibt, readdir verwenden, also einfach
Code: (dl )
<CURDIR>
durch
Code: (dl )
readdir(*CURDIR)
ersetzen. Den '*' als Typindikator für einen Typeglob kannst du natürlich auch weglassen.

Verwendest du zum Öffnen des Verzeichnisses die "modernere" Syntax
Code: (dl )
opendir(my $curdir, '.')
, so enthält die lexikalische Skalarvariable $curdir danach eine Referenz auf einen anonymen Typeglob. Das siehst du auch, wenn du zum Beispiel mal
Code: (dl )
perl -le 'opendir my $d, "."; print ref $d'
ausführst. Eigentlich ist es aber auch gar nicht so wichtig, was in der Variable hinterher drinsteckt. Viel wichtiger ist, dass man die Variable hinterher genauso wie ein Dateihandle verwenden kann, also einfach
Code: (dl )
readdir($curdir)
und ähnliches schreiben kann.

Mir ist schließlich noch eine Kleinigkeit aufgefallen: Da du mittels chdir in Unterverzeichnisse wechselst, solltest Du irgendwo auch mittels
Code: (dl )
chdir('..')
wieder zurückwechseln ;)
When C++ is your hammer, every problem looks like your thumb.
frodus
 2006-02-10 18:32
#62821 #62821
User since
2003-09-26
147 Artikel
BenutzerIn
[default_avatar]
Hi,

ich kann mich ja auch täuschen aber ist es möglich das
while(<FH>) nur mit einem FileHandle und nich mit einem
DirHandle funktioniert?

Versuch es mal so:
Code: (dl )
while(my $dirEntry = readdir(CURDIR)) {

Gruss,

Frodus

Murphy war einfach schneller aber immerhin ist meine Vermutung richtig :-)\n\n

<!--EDIT|frodus|1139589242-->
pq
 2006-02-10 19:28
#62822 #62822
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
Wiki:Was ist ein lexikalischer Filehandle?
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
supersucker
 2006-02-10 19:49
#62823 #62823
User since
2005-03-17
118 Artikel
BenutzerIn
[default_avatar]
leute,

dickes danke schön für die hilfe, jetzt tut das so wie ich will....

Quote
Genau da liegt auch das Problem, denn ein Verzeichnishandle kann nicht mit readline ausgelesen werden. Du musst stattdessen, wie es vayu in seinem Beispiel schreibt, readdir verwenden, also einfach


da wäre ich nicht draufgekommen, ist auch irgendwie nicht wirklich intuitiv einleuchtend oder?

Quote
Mir ist schließlich noch eine Kleinigkeit aufgefallen: Da du mittels chdir in Unterverzeichnisse wechselst, solltest Du irgendwo auch mittels
Code
chdir('..')
wieder zurückwechseln ;)


ja, das ganze ding bedarf noch mal einer grundlegenden überarbeitung.....:-)

danke soweit!
<< >> 10 Einträge, 1 Seite



View all threads created 2006-02-09 21:07.