Manfred Kuhn: Dateien dursuchen mit Dateiliste.

Hallo zusammen.

Stehe gerade vor einem Problem und weiss nicht weiter, hoffe ihr könnt mir ein bisschen helfen.

Zu meinem Problem:
Ich habe eine txt-Datei in der mehrere Dateinamen aufgelistet sind (ein Dateiname pro Zeile).
Nun möchte ich die txt-Datei durchlaufen lassen und nacheinander die Dateien öffnen und diese durchsuchen. Leider bekomme ich eine Fehlermeldung.

Mein Code (ungetestet):

#!/usr/bin/perl -w
my $dateiliste = "dateiliste.txt";
my $dateiname;
my $suche;
my $suchwort = "Doktor";
open my $holedateinamen, "<", $dateiliste;
while ($dateiname = <$holedateinamen>)
{
        open my $durchsuchen, "<", $dateiname;
        while ($suche = <$durchsuchen>)
        {
                 if ($suche =~ /$suchwort/)
                 {
                         print "Treffer";
                 }
        }
        close $durchsuchen;
}
close $holedateinamen;

--------

Ich bekomme im Interpreter folgende Fehlermeldung:
readline() on closed filehandle $durchsuchen ...

Wo liegt der Fehler?

Herzlichen Dank im vorraus.

MfG Kuhn.

  1. Ich habe eine txt-Datei in der mehrere Dateinamen aufgelistet sind (ein Dateiname pro Zeile).
    Nun möchte ich die txt-Datei durchlaufen lassen und nacheinander die Dateien öffnen und diese durchsuchen. Leider bekomme ich eine Fehlermeldung.

    Frage.
    Befinden sich die textdatei und die zu öffnenden Dateien im gleichen Verzeichnis?

    Mein Code (ungetestet):

    #!/usr/bin/perl -w

    use strict;

    my $dateiliste = "dateiliste.txt";
    my $dateiname;
    my $suche;
    my $suchwort = "Doktor";
    open my $holedateinamen, "<", $dateiliste;

    Und was machst du mit einem Fehler?

    while ($dateiname = <$holedateinamen>)

    Bist du sicher, dass dein Dateiname eine Newline "\n" am Ende hat ?

    {
            open my $durchsuchen, "<", $dateiname;

    und was machst du im Fehlerfall?

    while ($suche = <$durchsuchen>)
            {
                     if ($suche =~ /$suchwort/)

    Wer oder was definiert dieses Suchwort?
    Bist du sicher, dass du eine RE verwenden willst, wenn index() das Mittel der Wahl wäre?

    {
                             print "Treffer";

    Wenn du den Buffer nicht unflushed hast, dann siehst du eh nix
    bis zur nächsten gedruckten newline.

    }
            }
            close $durchsuchen;
    }
    close $holedateinamen;


    Ich bekomme im Interpreter folgende Fehlermeldung:
    readline() on closed filehandle $durchsuchen ...

    Wo liegt der Fehler?

    Reden wir von Plural.
    Du denkst nicht daran, dass du zweimal das gleiche File öffnest.

    mfg Beat

    --
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
    1. Frage.
      Befinden sich die textdatei und die zu öffnenden Dateien im gleichen Verzeichnis?

      Ja, liegen sie.

      Bist du sicher, dass dein Dateiname eine Newline "\n" am Ende hat ?

      Wie meinst du das jetzt?

      Bist du sicher, dass du eine RE verwenden willst, wenn index() das Mittel der Wahl wäre?

      Erstmal sollte das Script laufen, dann wird es verbessert.

      Reden wir von Plural.
      Du denkst nicht daran, dass du zweimal das gleiche File öffnest.

      Tu ich doch gar nicht?

  2. Mein Code (ungetestet):

    #!/usr/bin/perl -w

    use strict;

    wäre noch gut.

    my $dateiliste = "dateiliste.txt";
    my $dateiname;
    my $suche;
    my $suchwort = "Doktor";
    open my $holedateinamen, "<", $dateiliste;

    Hier solltest du natürlich testen, ob open erfolgreich war:
    open my $holedateinamen, "<", $dateiliste || die "Kann *$dateiliste* nicht öffnen. Grund: $!";

    while ($dateiname = <$holedateinamen>)
    {
            open my $durchsuchen, "<", $dateiname;

    Hier genauso.
    open my $durchsuchen, "<", $dateiname|| die "Kann *$dateiname* nicht öffnen. Grund: $!";

    Ich bekomme im Interpreter folgende Fehlermeldung:
    readline() on closed filehandle $durchsuchen ...

    Wo liegt der Fehler?

    Das müßte die Meldung sagen.

    Struppi.

    1. Hallo Struppi!

      Hier solltest du natürlich testen, ob open erfolgreich war:
      open my $holedateinamen, "<", $dateiliste || die "Kann *$dateiliste* nicht öffnen. Grund: $!";

      Der Richtigkeit halber:

      || nur mit Klammerung für open (Präzedenz)! Im folgenden existiert a.txt nicht:

      C:>perl -w

      open FH, "<", "a.txt" || die "Kann *a.txt* nicht öffnen. Grund: $!";  
      while(<FH>) { print }
      

      ^Z
      readline() on closed filehandle FH at - line 2.

      Dagegen:

      C:>perl -w

      open FH, "<", "a.txt" or die "Kann *a.txt* nicht öffnen. Grund: $!";  
      while(<FH>) { print }
      

      ^Z
      Kann *a.txt* nicht öffnen. Grund: No such file or directory at - line 1.

      oder:

      C:>perl -w

      open (FH, "<", "a.txt") || die "Kann *a.txt* nicht öffnen. Grund: $!";  
      while(<FH>) { print }
      

      ^Z
      Kann *a.txt* nicht öffnen. Grund: No such file or directory at - line 1.

      Viele Grüße aus Frankfurt/Main,
      Patrick

      --
      _ - jenseits vom delirium - _

         Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
      J'ai 10 ans! | Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
  3. Hallo Manfred!

    Mein Code (ungetestet):

    ^^^^^^^^^^

    ??

    Normalerweise posten Antwortende, die wenig Zeit haben, ungetesten Code... Wenn Du eine Lösung zu einem Problem hast, solltest Du schon den Code posten, der »getestet« zu Problemen führt... Seltsam, das.

    #!/usr/bin/perl -w
    my $dateiliste = "dateiliste.txt";
    my $dateiname;
    my $suche;
    my $suchwort = "Doktor";
    open my $holedateinamen, "<", $dateiliste;
    while ($dateiname = <$holedateinamen>)
    {
            open my $durchsuchen, "<", $dateiname;
            while ($suche = <$durchsuchen>)
            {
                     if ($suche =~ /$suchwort/)
                     {
                             print "Treffer";
                     }
            }
            close $durchsuchen;
    }
    close $holedateinamen;

    Aber wie auch immer, viel Redundanz in Deinem Code. Erstens fehlt:
    use strict;

    Dann unternimmst Du keinerlei Überprüfungen. Kürzer ginge es so:

    #!/usr/bin/perl -w  
      
    use strict;  
    my $suchwort = qr/Doktor/;  # quoted regexp (Muster vorkompiliert)  
    open LIST, "<", "dateiliste.txt" or die "Kann 'dateiliste.txt' nicht öffnen, weil: $!"; # überprüfung  
    while (<LIST>)  
    {  
            open FILE, "<", $_ or die "Datei $_ konnte nicht geöffnet werden, weil $!"; # Nutzung der Variable $_; Überprüfung  
            while (<FILE>)  
            {  
                             print "Treffer" if $_ =~ /$suchwort/;  
            }  
            close FILE;  
    }  
    close LIST;
    

    Das waren nur Anmerkungen zu dem Code, den _ich_ jetzt nicht getestet habe.

    Viele Grüße aus Frankfurt/Main,
    Patrick

    --
    _ - jenseits vom delirium - _

       Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
    J'ai 10 ans! | Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
    1. Hallo Manfred!

      »» Mein Code (ungetestet):
                    ^^^^^^^^^^

      ??

      Normalerweise posten Antwortende, die wenig Zeit haben, ungetesten Code... Wenn Du eine Lösung zu einem Problem hast, solltest Du schon den Code posten, der »getestet« zu Problemen führt... Seltsam, das.

      Ich sitze an dem PC meiner Tochter da auf meinem PC im moment kein Internet-Zugang ist. Möchte weder eine CD verschwenden, noch ein USB-Stick dafür kaufen oder mir ein Disketten-Laufwerk zulegen.

      In meinem Code gibt es zu jeder Aktion eine Fehlerbehandlung, auch use strict benutze ich.

      1. Hallo Manfred!

        Ich sitze an dem PC meiner Tochter

        Da könntest Du auch Perl installieren...

        da auf meinem PC im moment kein Internet-Zugang ist

        Braucht man, um ein Skript zu testen, auch nicht, es sei denn, man will die Ausgabe im Browser überprüfen (CGI-Skripte). Aber da hilft ein lokaler Webserver.

        Möchte weder eine CD verschwenden, noch ein USB-Stick dafür kaufen oder mir ein Disketten-Laufwerk zulegen.

        ??

        In meinem Code gibt es zu jeder Aktion eine Fehlerbehandlung, auch use strict benutze ich.

        Das können wir nicht erraten. Hast Du gemerkt, dass Du von allen Antwortenden ähnliche Antworten erhalten hast?

        Viele Grüße aus Frankfurt/Main,
        Patrick

        --
        _ - jenseits vom delirium - _

           Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
        J'ai 10 ans! | Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
        1. ??

          Wollte mich nur rechtfertigen ;-)

          Das können wir nicht erraten. Hast Du gemerkt, dass Du von allen Antwortenden ähnliche Antworten erhalten hast?

          Ja, ich sollte mich mehr auf die Fehlerbehandlung konzentrieren. Aber in meinen Augen ist alles richtig.
          Wenn nur ein Dateiname in der Liste ist wird alles korrekt ausgeführt aber sobald 2 oder mehr in der Liste stehen bekomme ich immer die "readline() on closed filehandle ...." Fehlermeldung.
          Verstehe nicht warum bzw. was ich falsch mache .

          MfG

          1. Verstehe nicht warum bzw. was ich falsch mache .

            Das steht in der Fehlermeldung, wenn du den Rückgabewert von open prüfst.

            Struppi.

          2. Hallo Manfred!

            Verstehe nicht warum bzw. was ich falsch mache .

            Ich auch nicht, aber fakt ist: »Dann machst Du irgendwas falsch« (© by Struppi) ;)

            Schau:

            C:>perl -w

            use strict;  
            my $suchwort = qr/Doktor/i;  # quoted regexp (Muster vorkompiliert)  
            open LIST, "<", "a.txt" or die "Kann 'a.txt' nicht öffnen, weil: $!"; # überprüf  
            ung  
            while (<LIST>)  
            {  
                    chomp;  
                    open FILE, "<", $_ or die "Datei $_ konnte nicht geöffnet werden, weil $  
            !"; # Nutzung der Variable $_; Überprüfung  
                    while (<FILE>)  
                    {  
                                     print "Treffer\n" if $_ =~ /$suchwort/;  
                    }  
                    close FILE;  
            }  
            close LIST;
            

            ^Z
            Treffer
            Treffer
            Treffer

            Inhalt a.txt:
            b.txt
            c.txt
            d.txt

            Inhalt b.txt:
            Doktoranten
            Doktorspiele

            Inhalt c.txt:
            Doktor Livingstone, nehme ich an?
            Dr. Schweitzer
            Dr. Mabuse

            Inhalt d.txt:
            Hier ist kein Arzt!
            Da auch nicht!

            Also insgesamt aus allen Dateien drei Zeilen, die das Suchwort »Doktor« beinhalten. Mein Skript liefert drei Mal »Treffer«.

            Erinnere Dich daran, was Dir Beat gestern sagte: »Bist du sicher, dass dein Dateiname eine Newline "\n" am Ende hat ?« - das fehlte in meiner ersten Antwort (ja, Beat und Struppi waren gestern schneller beim Tippen ;)) und wird jetzt berücksichtigt (chomp).

            Viele Grüße aus Frankfurt/Main,
            Patrick

            --
            _ - jenseits vom delirium - _

               Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
            J'ai 10 ans! | Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
            1. Erinnere Dich daran, was Dir Beat gestern sagte: »Bist du sicher, dass dein Dateiname eine Newline "\n" am Ende hat ?« - das fehlte in meiner ersten Antwort (ja, Beat und Struppi waren gestern schneller beim Tippen ;)) und wird jetzt berücksichtigt (chomp).

              Genau das müßte ihm auffallen, wenn er open prüft und die Fehlermeldung wie ich sie vorgeschlagen habe einbaut.

              Struppi.

            2. while (<LIST>)
              {
                      chomp;
                      open FILE, "<", $_ or die "$!") !";

              Nutzung der Variable $_; Überprüfung

              while (<FILE>)
                      {
                                       print "Treffer\n" if $_ =~ /$suchwort/;
                      }
                      close FILE;
              }

              ...

              Hi Patrick.
              In deinem Code bekommen Dokoren Hochkonjunktur.
              Faulheit wird irgendwann bestraft ;)

              while($x){
                  while($y){
                     do($_);
                  }
              }

              Auf was bezieht sich $_?
              Da habe ich schon Überraschungen erlebt.
              Bei verschachtelten Loops doch deshalb einmal
              besser mit einer benannten Alias Variable arbeiten.

              while my $u ($x){
                  while ($y){
                     do($_,$u);
                  }
              }
              Alles Ok jetzt.
              Allgemeine Regel:
              Reserviere $_ für die innerste Loop.

              mfg Beat

              --
              ><o(((°>           ><o(((°>
                 <°)))o><                     ><o(((°>o
              Der Valigator leibt diese Fische
              1. Hallo Beat!

                In deinem Code bekommen Dokoren Hochkonjunktur.

                Der OP wollte ja unbedingt einen Doktor ;)

                Dank meiner großen Allgemeinbildung (KAS[1]) konnte ich mich an den Spruch »Dr. Livingstone, nehme ich an?« erinnnern, von dem ich dachte, es sei der Titel eines Buchs oder Films. Ist aber anscheinend doch nicht. Dass es mit Afrika und Kongo zu tun hatte, wußte ich aber noch, wer weiß aber, wann und in welchem Zusammenhang ich diesen Satz hörte... - aber Fakt ist, dass wirklich: »La culture, c'est ce qui reste quand on a tout oublié« ;)

                Dr. Schweitzer war auch in Afrika und hieß genauso Albert wie Einstein.

                Dr. Mabuse abused von seiner Macht...

                Doktorspiele hat wohl jede(r) erlebt, die machen aber lange niemanden zum Doktoranden, den man besser doch mit »d« schreibt.

                while($x){
                    while($y){
                       do($_);
                    }
                }

                Auf was bezieht sich $_?

                Auf das innere »while«?

                Reserviere $_ für die innerste Loop.

                Ist es nicht ohnehin schon so?

                [1] KAS = Klopf auf Schulter (wenn's sonst keiner tut)

                Viele Grüße aus Frankfurt/Main,
                Patrick

                --
                _ - jenseits vom delirium - _

                   Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
                J'ai 10 ans! | Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
            3. Vielen Dank euch allen der Fehler war das fehlende chomp.

              Wenn ich noch eine frage stellen dürfte:
              Für was steht das "qr" bei my $suchwort = qr/Doktor/i;?

              Finde keine hilfreichen Erklärungen bei Google, weiss bis jetzt nur das es ein "Regexp Quote-Like Operator" ist.
              Kann mir das bitte jemand kurz erklären oder mir ein Link zu einer Webseite geben bei der das erklärt wird - natürlich auf Deutsch?

              MfG

              1. Hallo Manfred!

                Wenn ich noch eine frage stellen dürfte:
                Für was steht das "qr" bei my $suchwort = qr/Doktor/i;?

                Ich hab's in meiner ersten Antwort notiert: quoted regexp, Muster vorkompiliert.

                Das ist bei einem einfachen Suchmuster wie »Doktor« nicht unbedingt notwendig, aber man kann auch kompliziertere Suchmuster zuweisen, die möglicherweise vorkompiliert werden (Zitat: and possibly compiles), und so die Performance der später eingesetzten Regexp erhöhen.

                Finde keine hilfreichen Erklärungen bei Google

                http://www.google.com/search?q=perldoc+quoted+regex -> erster Treffer ist bereits perldoc perlop

                weiss bis jetzt nur das es ein "Regexp Quote-Like Operator" ist.

                Richtig.

                natürlich auf Deutsch?

                Da kannst Du lange suchen, leider. Da die meisten Perlhacker aus deutschem Lande des Englischen mächtig sind, hat es keiner nötig, perldoc zu übersetzen. Das sieht auf der anderen Seite des Rheins anders aus: http://perl.enstimac.fr/DocFr/perlop.html...

                Und eben stelle ich fest, dass die wenigen deutschen Übersetzungen mittlerweile nur noch gegen Username/Passwort erreichbar sind, traurig, traurig, traurig... (der Link hier [(...) als die _Deutschen_] funktionierte damals noch).

                Viele Grüße aus Frankfurt/Main,
                Patrick

                --
                _ - jenseits vom delirium - _

                   Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
                J'ai 10 ans! | Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
              2. Wenn ich noch eine frage stellen dürfte:
                Für was steht das "qr" bei my $suchwort = qr/Doktor/i;?

                Finde keine hilfreichen Erklärungen bei Google, weiss bis jetzt nur das es ein "Regexp Quote-Like Operator" ist.
                Kann mir das bitte jemand kurz erklären oder mir ein Link zu einer Webseite geben bei der das erklärt wird - natürlich auf Deutsch?

                Einige Beispiele

                1.
                for (1..1000){
                  $x =~ /$u$v$z/;
                }
                Der Ausdruck muss 1000 mal kompiliert werden,

                2.
                my $re = qr/$u$v$z/;
                for (1..1000){
                  $x =~ $re;
                }
                Die Reguläre Expression wird nur einmal kompiliert.

                In qr// kannst du also ganze REs oder Teile davon speichern.

                Natürlich kann ich auch schreiben

                3.
                my $string = $u.$v.$w
                for (1..1000){
                  $x =~ /$string/;
                }
                Aber hier muss in minderem Masse dennoch die 1000x kompiliert werden.

                4.
                for (1..1000){
                  $x =~ /$string/o;
                }
                verbessert das m//o kompliere nur beim ersten Schleifendurchgang.

                Mit qr kannst du die Schalter qr//smix verwenden.

                mfg Beat

                --
                ><o(((°>           ><o(((°>
                   <°)))o><                     ><o(((°>o
                Der Valigator leibt diese Fische