xNeTworKx: Logikproblem bei Zuweisung

Hallo,
ich sitze nun seit 2 Stunden an einer Schleife und komm nicht weiter. Ich will die 2 zuletzt geänderten Dateien im Ordner lassen, und die restlichen verschieben. Es klappt wunderbar, aber nur bei der zuletzt geänderten. Die zu vorletzt geänderte Datei ist nicht die, die im Ordner belassen wird, aber wieso ? Ich poste hier mal die letzten relevanten Schleifen, wobei ich glaube, daß die erste Schleife schuld ist:

(zur Info : Die Dateien sind jeweils in einem Hash angelegt, wobei der Name der Datei der Schlüssel ist, und der Inhalt der Wert)

foreach my $key(keys %hash)  {
    if (-M $key gt "$zuletzt_geaendertes")  {
    $vorletztes = $zuletzt_geaendertes;
    $zuletzt_geaendertes = $key;
    }
}
foreach my $key(keys %hash)  {
    if ($key ne $zuletzt_geaendertes)  {
         if ($key ne $vorletztes)  {
               if (!-e "$schreibordner")  {
       mkdir("$schreibordner");
       }
         open(FILE,">$schreibordner/$key") or die "Kann $key nicht in neuen Ordner schreiben : $!\n";
         flock FILE, 2;
         print FILE $hash{$key};
         close FILE;

unlink "$leseordner/$key";
         }
    }
}

$xNeTworKx.

  1. Hi,

    foreach my $key(keys %hash)  {
        if (-M $key gt "$zuletzt_geaendertes")  {

    wenn ich Dich richtig interpretiere, steht in $zuletzt_geaendertes der _Name_ der Datei, nicht das Änderungsdatum. Ferner ist gt ein String-Operator, d.h. Du schaust hier, ob die _Zeichenkette_ "10539823" (z.B.) größer als "datei.bla" ist.

    Ferner beachte bitte

    perldoc perlfaq4
    What's wrong with always quoting "$vars"?

    Cheatah :-)

    1. Hallo,

      wenn ich Dich richtig interpretiere, steht in $zuletzt_geaendertes der _Name_ der Datei, nicht das Änderungsdatum.

      Das stimmt.

      Ferner ist gt ein String-Operator, d.h. Du schaust hier, ob die _Zeichenkette_ "10539823" (z.B.) größer als "datei.bla" ist.

      Ok, jetzt vergleiche ich die beiden Änderungsdaten, aber :

      foreach my $key(keys %hash)  {
          if (-M $key gt -M $zuletzt_geaendertes)  {
          $vorletztes = $zuletzt_geaendertes;
          $zuletzt_geaendertes = $key;
          }
      }

      manchmal habe ich noch immer eine der beiden Dateien falsch, aber wieso ?

      What's wrong with always quoting "$vars"?

      ich glaube ich weis was du meinst, aber ich speichere keine exakten Zahlen, sondern ich speichere nur die Dateinamen, und denen ist egal, wie viel Stellen nach . die Zahl hat.

      $xNeTworKx.

      1. Hi,

        Ferner ist gt ein String-Operator, [...]

        Ok, jetzt vergleiche ich die beiden Änderungsdaten, aber :
            if (-M $key gt -M $zuletzt_geaendertes)  {
        manchmal habe ich noch immer eine der beiden Dateien falsch, aber wieso ?

        weil gt noch immer ein String-Operator ist. "9" gt "10000", weil "9" einen höheren ASCII-Wert hat als "1".

        What's wrong with always quoting "$vars"?
        ich glaube ich weis was du meinst, aber ich speichere keine exakten Zahlen, sondern ich speichere nur die Dateinamen, und denen ist egal, wie viel Stellen nach . die Zahl hat.

        Nein, ich meine, dass es den Perl-Interpreter nur Zeit kostet, aus "$var" $var zu extrapolieren. Das ist so, als würdest Du eine Subroutine aufrufen:

        sub giveback {
            return @_;
        }

        Du bekommst genau das zurück, was Du reingibst, hast dabei aber nur Zeit verschwendet. Ergo: Die Doublequotes, die Du in der ersten Variante stehen hattest, waren überflüssig wie ein Kropf :-)

        Cheatah

        1. Hi,
          ich möchte dir noch ein anderes Script zeigen, wo aber das gleiche Problem auftritt, aber diesmal habe ich > statt gt usw genommen. Einer, der beiden Dateien, die im Ornder bleibt, ist trotzdem falsch (also ist nicht die letzte und vorletzt , sondern meistens die letzte und irgend eine andere.)

          #!/usr/bin/perl -w

          use strict;
          my $leseordner = '.';
          my $schreibordner = 'neuer';

          my @array;
          #my $vorletzte_datei = 0;
          my $dateizaehler = 0;
          my $i = 0;
          my $hoechste = 0;
          my $neueste_datei = 0;
          my @dateiliste;

          opendir(DIR,$leseordner) or die "Kann Leseordner nicht oeffnen : $!\n";
              while (defined(my $file = readdir(DIR)))   {
                       if ($file =~ /^(\d+?_)(\d+?)(..{1,5})$/)   {
                push @dateiliste, $file;
                $array[$i][0] = $1;
                       $array[$i][1] = $2;
                $array[$i][2] = $3;
                    open(FILE,"$leseordner/$file") or die "Kann $file nicht oeffnen : $!\n";
             local $/;
             my $inhalt = <FILE>;
             close FILE;
               $array[$i][3] = $inhalt;
               $i++;
               $dateizaehler++;
                       }
              }
          closedir DIR;

          for (my $i = 0; $i < $dateizaehler; $i++)  {
               if ($array[$i][1] > $hoechste)  {
               $hoechste = $array[$i][1];
              # $vorletzte_datei = $neueste_datei;
               $neueste_datei = $array[$i][0].$array[$i][1].$array[$i][2];
               }
          }
          $i = 0;
          foreach my $file(@dateiliste)  {
                 if ($file ne $neueste_datei)  {
                     # if ($file ne $vorletzte_datei)  {
                      open(FILE,">$schreibordner/$file") or die "Kann $file nicht in neuen Ordner schreiben : $!\n";
                      flock FILE, 2;
                      print FILE $array[$i][3];
                      close FILE;
                      unlink "$leseordner/$file";
            #  }
                  }
          $i++;
          }

          $xNeTworKx.

          1. Hi,

            ich möchte dir noch ein anderes Script zeigen, wo aber das gleiche Problem auftritt, aber diesmal habe ich > statt gt usw genommen. Einer, der beiden Dateien, die im Ornder bleibt, ist trotzdem falsch (also ist nicht die letzte und vorletzt , sondern meistens die letzte und irgend eine andere.)

            hast Du Dir die entsprechenden Werte des Arrays mal sinnvoll ausgeben lassen?

            if ($file =~ /^(\d+?_)(\d+?)(..{1,5})$/)   {

            Die Werte in den Klammern enthalten auch nicht-Zahlzeichen, oder beginnen im Fall $3 mit einem Kommazeichen (und einem beliebigen Zeichen, z.B. Buchstaben). Du versuchst jedoch, sie als vollständige Zahlen anzusehen. Das kann schon für "Verwirrung" sorgen!

            Achte darauf, dass Du _exakt_ die Zeichenketten im Array abspeicherst, die Du auch brauchst.

            # $vorletzte_datei = $neueste_datei;

            Dass dies auskommentiert ist, hat seine Richtigkeit?

            Btw: Vielleicht willst Du perldoc -f sort (oder auch den entsprechenden Abschnitt von perldoc perlfaq4) lesen. Wenn Du "einfach nur" das Array nach Deinen Wunsch-Kriterien sortierst, sparst Du Dir das "merk Dir das letzte und das vorletzte"-Gehacksel, weil Du nämlich einfach die ersten bzw. letzten beiden Elemente verwendest. Oder die ersten bzw. letzten drei, wenn Du auf einmal mehr brauchst.

            Cheatah

            1. hallo,

              if ($file =~ /^(\d+?_)(\d+?)(..{1,5})$/)   {

              Die Werte in den Klammern enthalten auch nicht-Zahlzeichen, oder beginnen im Fall $3 mit einem Kommazeichen (und einem beliebigen Zeichen, z.B. Buchstaben). Du versuchst jedoch, sie als vollständige Zahlen anzusehen. Das kann schon für "Verwirrung" sorgen!

              Achte darauf, dass Du _exakt_ die Zeichenketten im Array abspeicherst, die Du auch brauchst.

              ich weis. ich brauche das Erste Element auch nicht ,sondern es wird nur nach dem 2. sortiert.

              # $vorletzte_datei = $neueste_datei;

              Dass dies auskommentiert ist, hat seine Richtigkeit?

              Ja, ich habe es mal weggelassen, daß die vorletzte Datei auch ausgegeben wird, weil es nicht richtig funktioniert hat.

              $xNeTworKx.

              1. Hi,

                ich weis. ich brauche das Erste Element auch nicht ,sondern es wird nur nach dem 2. sortiert.

                tja, wenn Du sortieren möchtest, solltest Du das tun ;-)

                Cheatah

  2. Hi,

    ich sitze nun seit 2 Stunden an einer Schleife und
    komm nicht weiter.

    hm ... wie viele Dateien sind das denn so? Ein Dutzend
    oder ein paar tausend?

    Falls es nicht zu viele sind, schlage ich eine nicht
    ganz performance-optimierte, aber intellektuell ein-
    fache Lösung vor:
    1. Speichere einen Abbildung von Änderungsdatum zu
       Dateiname. Achte dabei darauf, daß das Änderungs-
       datum eindeutig ist - hänge ggf. einen eindeutigen
       Tie-breaker hinten dran. (Also etwa:
          sprintf ('%10d%10d', $datum, ++$tiebreaker)
       als Hash-Index.)
    2. Sortiere diese Abbildung numerisch;
       extrahiere die beiden höchsten Werte.
    3. Prüfe für jede Datei, ob ihr Name mit einem der
       beiden ausgewählten Namen übereinstimmt; wenn nein,
       verschiebe sie.

    Sortieren kann performance-mäßig suboptimal sein, wenn
    Du größere Dateianzahlen hast.

    Meine Skizze führt aber dazu, daß Du zu jedem Zeit-
    punkt sehr genau weißt, was Du tust und warum Du es
    tust. Und das Programm ist sehr leicht zu ändern,
    falls Du irgendwann mal drei Dateien aufheben willst.

    Viele Grüße
          Michael

    1. Hi,

      ja ich weis, es ist nicht besonders effizient, aber ich bemühe mich stets das in mir meinen Rahmen Mögliche zu tun, um relativ effizient zu arbeiten. Ich bin stets gern offen für bessere Lösungen.

      $xNeTworKx.