wie kann man mit Hilfe von perl Boardmitteln (also ohne sed oder awk, etc)
ein gegebenes Verzeichnis und seinen Unterverzeichnissen durchlaufen und
dabei
eine bestimmte zeile in den Dateien aendern, bzw. ersetzen. Also z.B. die
Zeile:
#!/usr/bin/perl
in ein
#!/usr/local/bin/perl
aendern/eretzen?
Thomas
Also wenn es sich nur um eine Zeile handelt, w�rde ich immer
perl -pi -e 's/alt/neu/' *
vorschlagen. Das tuts aber nur f�r alle Dateien im Verzeichnis - und ist
ja auch sozusagen nicht "innerhalb" von Perl.
Innerhalb von Perl: ich w�rde wohl File::Find verwenden. In dem Code,
den du find �bergibst, musst du dann selbst die Dateien �ndern. Also ich
w�rde dann eine neue Datei �ffnen, die ge�nderten Daten da rein
schreiben und schlie�lich die alte Datei l�schen und die neu erstellte
dann umbenennen.
- Wolf
zB so mit rekursiver Funktion:
#!/usr/bin/perl -w
$subs = 's:^#!/usr/bin/perl:#!/usr/local/bin/perl:';
$dir = 'gegeben';
rs($dir);
sub rs {
my $dir = shift;
my ($file,@files,$fp);
if (opendir $dir,$dir) {
while ($file = readdir $dir) {
next if $file eq '.' or $file eq '..';
$fp = "$dir/$file";
if (-d $fp) {
rs($fp);
} elsif (-f $fp) {
push @files,$fp;
}
}
closedir $dir;
system qw(perl -p -i -e),$subs,@files if @files;
} else {
warn "cannot open $dir : $!\n";
}
}
--
Ullrich Horlacher Informationssysteme und Serverbetrieb
Rechenzentrum E-Mail: horl...@rus.uni-stuttgart.de
Universitaet Stuttgart Tel: ++49-711-685-65868
Allmandring 30 Fax: ++49-711-682357
70550 Stuttgart (Germany) WWW: http://www.rus.uni-stuttgart.de/
>> [...]
> zB so mit rekursiver Funktion:
> #!/usr/bin/perl -w
> [...code...]
ja super, damit klappt es ganz gut und soweit konnte ich es
auch nachvollziehen. Danke fuer den Hinweis. Die Ersetzung
geht bei mir nicht so (Windows und Strawberry Perl), aber
mache da wohl besser einen anderen Thread auf, da ich nach
tagelangem Suchen nicht weiter komme.
Ich habe jetzt in Bezug auf Rekusion noch ein Verstaendnisproblem.
Zum einen ist ja opendir(DIRHANDLE, $dirname) definiert
und erst neuere (btw: ab wann?) perl Interpreter koennen auch
eine Referenz statt dem DIRHANDLE nutzen.
Jetzt ist es aber auch so das mir ein use strict das Verwenden einer
Referenz verbieten _wuerde_.
Wie kann ich das nun so machen, dass ich _keine_ Referenzen
auf das DIRHANDLE habe, sondern das DIRHANDLE selbst
_und_ use strict benutze, ohne das ich ein "no strict 'refs';"
setzen wuerde, um eben weiterhin eine starke Ueberpruefung
in dem Script beibehalten zu koennen.
Odr geht es nicht? Ich verstehe z.B. noch nicht wieso hier ein
readdir() attempted on invalid dirhandle DIR at shebang.pl line 22.
und
closedir() attempted on invalid dirhandle DIR at shebang.pl line 30.
kommt. Bzw. wird doch in jedem rekursiven Aufruf zwar der
$dirname uebergeben, aber dann doch wieder mit dem DIR Handle
_neu_ geoeffnet - genauso wie beim ersten Aufruf - oder? Und warum
wird dann die Rekursion abgebrochen?
Im Prinzip habe ich es genauso wie oben. Uueberpruefe aber noch auf
Textdatei und will dann erst eine Aktion auf die Datei loslasse).
Die Funktion filemod() ist jetzt aber nicht so wichtig.
Mich interessiert jetzt mehr warum die Rekursion nicht mit
dem DIRHANDLE funkt.
Teilweise kann ich die Fehler "abfedern", wenn ich vor closedir nochmal
schaue, ob der Datei-Pointer, bzw. variable auch auf ein Verzeichnis zeigt.
---snip---
#!perl -w
use strict;
#no strict 'refs';
use warnings;
use Cwd;
my $i = 0;
my @files;
my $dir = cwd;
recursive($dir);
filemod(\@files);
sub recursive {
$dir = shift; # @_
my ($file, $fp);
if( opendir(DIR, $dir) ) { #|| die("Can't open $dir: $!\n");
while( $file = readdir(DIR) ) {
next if( $file eq '.' || $file eq '..' );
$fp = "$dir/$file";
if( -d $fp ) {
recursive($fp);
}
elsif( -f $fp ) {
push(@files, $fp);
}
}
#if( -d $fp ) {
closedir(DIR);
#}
}else {
warn("Can't open $dir : $!\n");
}
} # end of recursive()
sub filemod {
if( defined($_[0]) ) {
my $tmp = $_[0];
foreach( @{$tmp} ) {
if( -T @{$tmp}[$i] ) {
print "@{$tmp}[$i]" , "\n";
}
$i++;
}
}
} # end of filemod()
---snap---
Thomas
> Also wenn es sich nur um eine Zeile handelt, w�rde ich immer
> perl -pi -e 's/alt/neu/' *
> vorschlagen. Das tuts aber nur f�r alle Dateien im Verzeichnis - und ist
> ja auch sozusagen nicht "innerhalb" von Perl.
Danke fuer den Hinweis. Und mit Rekursion wie es Ulli vorgeschlagen
hat bin ich schon ganz gut weitergekommen, aber ich habe noch ein
Problem beim Erstzen. Das ist aber auch wieder ein neues Problem
und ich mache da besser einen neuen Thread auf.
Thomas
> Ich habe jetzt in Bezug auf Rekusion noch ein Verstaendnisproblem.
>
> Zum einen ist ja opendir(DIRHANDLE, $dirname) definiert
> und erst neuere (btw: ab wann?) perl Interpreter koennen auch
> eine Referenz statt dem DIRHANDLE nutzen.
Sollte seit etwa 10 Jahren so funktionieren.
> Jetzt ist es aber auch so das mir ein use strict das Verwenden einer
> Referenz verbieten _wuerde_.
Lass use strict weg :-)
> Wie kann ich das nun so machen, dass ich _keine_ Referenzen
> auf das DIRHANDLE habe, sondern das DIRHANDLE selbst
Dann geht die Rekursion nicht, weil DIRHANDLE global ist.
> kommt. Bzw. wird doch in jedem rekursiven Aufruf zwar der
> $dirname uebergeben, aber dann doch wieder mit dem DIR Handle
> _neu_ geoeffnet
Ja.
> Mich interessiert jetzt mehr warum die Rekursion nicht mit
> dem DIRHANDLE funkt.
Rekursion benoetigt lokale Variablen.
Das ist in allen Programmiersprachen so.
a) es sollte in scripten AFAIK immer #!/usr/bin/perl sein, auch unter
Windowsen, die ignorieren die Zeile ja eh.
$ ls -l /usr{,/local}/bin/perl{,5.*}
[..] /usr/bin/perl -> /usr/local/bin/perl*
[..] /usr/bin/perl5.00503*
[..] /usr/local/bin/perl*
[..] /usr/local/bin/perl5.10.0*
[.. noch ein paar "Leichen" ..]
Wobei /usr/local/bin/perl{,5.10.0} hardlinks sind.
b) schau dir mal die Ausgabe von
perl -MO=Deparse -pi.bak -e 's/foo/bar/;'
an. Dann die *komplette* Beschreibung von '-i[extension]' in
'perldoc perlrun' und dann noch 'perldoc File::Find' und ᅵberlege,
was man alles in der "wanted" Funktion unterbringen kᅵnnte ... ;)
HTH,
-dnh
--
A rule for life.
echo 16i[q]sa[ln0=aln100%Pln100/snlbx]sbA0D4D465452snlb xq |dc
Wenn du perl perlprog.pl aufrufst, dann wird es schon ignoriert. Aber
wenn du z.B. unter Windows einen Apache hast, dann schaut der die Zeile
schon an und wirft dann natᅵrlich ggf. einen Fehler. Auch wenn man das
natᅵrlich mit "ScriptInterpreterSource registry" umgehen kann.
- Wolf
Auf Windosen mag das egal sein, aber auf Unixen *muss* in der
Shebang-Zeile der richtige Pfad drin stehen. Wenn das Perl, das Du
einsetzen willst, in /usr/local/bin/perl ist (z.B. weil /usr/bin/perl
die Uralt-Version ist, die der Vendor glaubt, ausliefern zu m�ssen),
dann darf da nat�rlich nicht /usr/bin/perl stehen.
hp