Alain: Ich kriegs nicht gebacken...mit flock

Guten Morgen,
Ich habe da ein beispiel an dem ich zur zeit nicht weiter komm.
Ich finde flock eine gute methode um daten zu schützen bevor sie von einem zweiten zugriff
benutzt werden,aber in meinem beispiel geht das wahrscheinlich nicht so
wie ich das will.
Ich möchte eine datei einlesen und beschreiben ohne dass der alte inhalt gelöscht wird
und diese datei sollte solange von anderen zugriffen geschützt sein bis
das einlesen sowie das geschriebene abgeschlossen ist.
Hier ist das beispiel:

sub check
{
use Fcntl ':flock'; #hier wird eingelesen ob das zu schreibende schon vorhanden ist
$Zugriffe = 0;
open(DATEN,"<$logfile") || &Dead('Cannot open file');
flock(DATEN,LOCK_EX);
while (<DATEN>){
 /$etwas_geschriebenes/ ? $Zugriffe = $Zugriffe + 1 : $Zugriffe = $Zugriffe;
     }
     if ($Zugriffe >= 1) #wenn es vorhanden ist
     {
     &Dead(); #dann verlasse den weiteren vorgang
     }
     else
     {
     close (DATEN);

##hier ist das problem,wo ein zweiter zugriff der die daten wieder einliest,
den weiteren vorgang stören könnte bzw. die daten dann nochmals schreibt,
weil er in dem moment bevor er die daten schreibt ja schon einliest
 und nicht weiss dass die daten bereits geschrieben wurden.##

open(DATEN,">>$logfile") || &Dead('Cannot open file'); #ansonsten schreibe den text in die log
     flock(DATEN,LOCK_EX);
     print DATEN "$etwas_geschriebenes\n";
     close (DATEN);
     &email();
     }
     }
------------
Das problem hatte ich als jemand in einer sekunde zweimal das script aufgerufen hatte.
Vielleicht gehts ja so,denn das script ist nun so (wie es oben steht abgeändert worden).
Oder weiss jemand eine bessere idee?
Grüsse
Alain

  1. Hi!

    close (DATEN);

    ##hier ist das problem

    Schon mal richtig erkannt. Gut, dann musst Du nur noch in http://forum.de.selfhtml.org/archiv/2002/6/13484/ die Loesung nachlesen. ;-)

    So long

    --
    "Microsoft ist über die Probleme informiert, hat aber noch nicht reagiert."
    "Der Patch %s, der das Problem %s beheben sollte, funktioniert offenbar nicht."
    "Wann ein Update verfügbar sein wird, ist nicht bekannt."
        (Textbausteine der Heise-Newsticker-Redaktion)
  2. Neben dem was Colocybe dir schon gezeigt hat...

    use Fcntl ':flock'; #hier wird eingelesen ob das zu schreibende schon vorhanden ist

    Das einbinden der Module ist übersichtlicher (IMHO) wenn man es am Anfang des Skriptes macht.

    $Zugriffe = 0;

    Du solltest DRINGEND use strict verwenden, da das dich gerade in der Entwicklungphase vor vielen vielen Fehlern bewahrt und dir beim Debuggen sehr hilft.
    Außerdem sollten Variabeln nicht mit einem Großbuchstaben beginnen http://perldoc.com/perl5.8.0/pod/perlstyle.html

    open(DATEN,"<$logfile") || &Dead('Cannot open file');

    Hier kannst du deiner Fehlerroutine noch $! mitgeben, dann weißt du auch warum dein Programm sterben musste.

    /$etwas_geschriebenes/ ? $Zugriffe = $Zugriffe + 1 : $Zugriffe = $Zugriffe;

    Das hatten wir doch letztens erst:
    Besser so:

    $Zugriffe = /$etwas_geschriebenes/ ? $Zugriffe + 1 : $Zugriffe;

    }
         if ($Zugriffe >= 1) #wenn es vorhanden ist
         {
         &Dead(); #dann verlasse den weiteren vorgang
         }
         else
         {
         close (DATEN);

    ##hier ist das problem,wo ein zweiter zugriff der die daten wieder einliest,
    den weiteren vorgang stören könnte bzw. die daten dann nochmals schreibt,
    weil er in dem moment bevor er die daten schreibt ja schon einliest
    und nicht weiss dass die daten bereits geschrieben wurden.##

    Das verstehe ich nicht. du flockst doch oben deine Datei, also kann kein zweiter Vorghang die Datei lesen/schreiebn (LOCK_EX = exklusiv).

    open(DATEN,">>$logfile") || &Dead('Cannot open file'); #ansonsten schreibe den text in die log
         flock(DATEN,LOCK_EX);
         print DATEN "$etwas_geschriebenes\n";
         close (DATEN);
         &email();
         }
         }

    Wenn du allerdings meinst, dass das im gleichen Programm passiert, dann musst du die Datei immer zum lesen+schreiben öffnen.

    Auch wenn's komplizierter ist, aber das ist CGI ;-)

    Struppi.

    1. hallo,
      Ein Danke an Colocybe und struppi für die ausf. infos.
      Sowas in der richtung "einmal lesen und schreiben alles in einem->schützen (flock)"
      bis der vorgang komplett abgeschlossen ist,zu benutzen,wollte ich.
      Ich hatte es versucht mit +> open aber ohne seek und truncate->(versteh ich nicht ganz)
      dann wurde allerdings der ganze alte inhalt gelöscht,was nicht sein durfte.
      Ausserdem möchte ich dass das zu schreibende nicht am anfang sondern
      am schluss (ganz unten angehängt wird mit einem zeilen umbruch).

      Wenn du allerdings meinst, dass das im gleichen Programm passiert, dann musst du die Datei immer zum lesen+schreiben öffnen.

      ja so soll es sein
      thx
      Alain

      1. bis der vorgang komplett abgeschlossen ist,zu benutzen,wollte ich.
        Ich hatte es versucht mit +> open aber ohne seek und truncate->(versteh ich nicht ganz)
        dann wurde allerdings der ganze alte inhalt gelöscht,was nicht sein durfte.
        Ausserdem möchte ich dass das zu schreibende nicht am anfang sondern
        am schluss (ganz unten angehängt wird mit einem zeilen umbruch).

        Wenn du wirklich nur anhängen willst dann reicht seek und seek musst du immer benutzen wen du eine Datei mit +< öffnest, da du nicht sicher sein kannst, dass der Zeiger am Anfang der Datei steht.

        Wenn du allerdings mittendrin was ändern willst, solltest du die Datei erst mit truncate (truncate schneidet ab der aktuellen Position die Datei ab) abschneiden und ab da neuschreiben.

        Struppi.

        1. hallo,
          Danke,alles klar nun,

          Wenn du wirklich nur anhängen willst dann reicht seek und seek musst du immer benutzen wen du eine Datei mit +< öffnest, da du nicht sicher sein kannst, dass der Zeiger am Anfang der Datei steht.

          Wenn du allerdings mittendrin was ändern willst, solltest du die Datei erst mit truncate (truncate schneidet ab der aktuellen Position die Datei ab) abschneiden und ab da neuschreiben.

          Dann werd ich es so mal versuchen.
          Aber kannst du mir noch sagen was genau z.B. seek (FILE, 0, 2);
                                                             bedeutet ^ ?
          grüsse vom
          Alain

          1. Dann werd ich es so mal versuchen.
            Aber kannst du mir noch sagen was genau z.B. seek (FILE, 0, 2);
                                                               bedeutet ^ ?

            hehe, dir hat noch keiner ein perldoc -f xxx entgegen geworfen?

            Du findest die Dokumentation von Perl auf deiner Festplatte (zur Not auch im Internet http://perldoc.com/perl5.8.0/pod/func/seek.html) und die solltest du auch mal ausführlich studiert haben, da steht ein Haufen Wissen drin, der nützlich ist falls du dich länger mit Perl beschäftigen möchtest.

            Struppi.

            1. hallo,

              hehe, dir hat noch keiner ein perldoc -f xxx entgegen geworfen?

              doch auch schon :)

              Also hier hab ich nun mein fertiges script das aber noch nicht richtig
              zu funktionieren scheint bzw. nicht beendet wird und dadurch den inhalt
              wieder löscht *nerv*

              Hier ist das beispiel:

              sub check
              {
              my $zugriff = 0;
              open(DATEN,"+>$logfile") || die "cannot open $!\n";
              flock(DATEN,LOCK_EX) || die "cannot lock $!\n";
              while (<DATEN>){
               /$etwas_geschriebenes/ ? $zugriff = $zugriff + 1 : $zugriff;
                   }
                   if ($zugriff >= 1)
                   {
                   &Dead(); #abruch
                   }
                   else
                   {
                   seek (DATEN, 0, 2);
                   print DATEN "$etwas_geschriebenes\n";
                   close (DATEN) || die "cannot close $!\n";
                   }
                   }

              Was ist denn hier nun falsch?
              Am Anfang steht dies

              #!/usr/bin/perl -Tw

              use CGI::Carp qw(fatalsToBrowser);
              use Fcntl ':flock';
              use strict;

              aber ich bekomm auch keine error meldung mit use strict.
              Gruss vom Alain

              1. hi Alian

                /$etwas_geschriebenes/ ? $zugriff = $zugriff + 1 : $zugriff;

                in dieser zeile steckt dein fehler dein $zugriff wird nicht erhöht .!?

                schreib das mal so $etwas_geschriebenes ? ($zugriff +=1) : ($zugriff);
                oder so wie Struppi es in seinem posting geschrieben hat

                bis bis roman

                --
                P.S. manchmal wundere ich mich schon über die postings (fragen u. antworten) die man hier geboten bekommt(meine eigenen [leider] mit eingenommen)
                => ich denke mir meinen teil und ziehe das beste daraus :-)
                1. hallo roman,

                  /$etwas_geschriebenes/ ? $zugriff = $zugriff + 1 : $zugriff;

                  in dieser zeile steckt dein fehler dein $zugriff wird nicht erhöht .!?

                  doch es geht (war ja auch von selfhtml abgeschrieben) :)
                  die tips von struppi haben mir sehr viel weiter geholfen und dementsprechend
                  hab ich auch ein paar scripts nun umgeändert bis jetzt - und alle laufen jetzt,sogar mit
                  "#!/usr/bin/perl -Tw
                  use strict;"

                  es war die paar stunden arbeit wert.
                  so long
                  Alain

              2. hehe, dir hat noch keiner ein perldoc -f xxx entgegen geworfen?

                doch auch schon :)

                aber nicht gelesen?

                Also hier hab ich nun mein fertiges script das aber noch nicht richtig
                zu funktionieren scheint bzw. nicht beendet wird und dadurch den inhalt
                wieder löscht *nerv*

                ist doch klar.

                my $zugriff = 0;
                open(DATEN,"+>$logfile") || die "cannot open $!\n";

                Hier öffnest du die Datei zum lesen und schreiben und löscht sie gleichzeitig (der '>' operator löscht die Datei)

                Du möchtest:
                open DATEN, "+<$logfile" || die "cannot open $logfile: $!\n";

                /$etwas_geschriebenes/ ? $zugriff = $zugriff + 1 : $zugriff;

                Du brauchst hier kein if else Konstrukt, wie ich weiter oben schon schrub:

                $zugriff++ if /$etwas_geschriebenes/;

                }
                     if ($zugriff >= 1)

                Da reicht dann:

                if($zugriff)

                {
                     &Dead(); #abruch

                Das '&' Zeichen ist Perl4 Syntax und sollte nur eingestzt werden, wenn du weißt warum (du übergibst damit soweit ich weiß deiner Funktion @_)

                }
                     else
                     {
                     seek (DATEN, 0, 2);

                Da du mich ja schon nach der 2 gefragt hast, man sollte auch hier die Konstanten aus fnctl verwenden, da die 2 nicht immer SEEK_SET sein muss.

                aber ich bekomm auch keine error meldung mit use strict.

                Das ist ja schon mal gut ;-)

                Struppi.

                1. hallo struppi,

                  wieder löscht *nerv*

                  ist doch klar.

                  oh mann kann ich dumm sein *Kopfkratz->langsamAngstkrieg*

                  Du möchtest:
                  open DATEN, "+<$logfile" || die "cannot open $logfile: $!\n";

                  jetzt gehts so :)

                  sub check
                  {
                  my $zugriff = 0;
                  open(DATEN,"+<$logfile") || Dead();
                  flock(DATEN,LOCK_EX) || die "cannot lock $!\n";
                  while (<DATEN>){
                  $zugriff++ if /$etwas geschriebenes/;
                       }
                       if ($zugriff)
                       {
                       Dead();
                       }
                       seek (DATEN, 0, 2);
                       print DATEN "$etwas geschriebenes\n";
                       close (DATEN) || die "cannot close $!\n";

                  }
                  ----------------
                  Ich dachte mir,man könnte z.B. das script direkt sterben lassen indem man z.B.
                  dies schreibt "dead() if /$etwas geschriebenes/;" anstatt $zugriff++ if...
                  aber das geht so nicht,ansosten könnte man dann auch auf den if zweig verzichten.

                  Da du mich ja schon nach der 2 gefragt hast, man sollte auch hier die Konstanten aus fnctl verwenden, da die 2 nicht immer SEEK_SET sein muss.

                  nach dem seek in form von fnctl habe ich nur http://www.perldoc.com/perl5.8.0/pod/func/seek.html etwas gesehen von
                  SEEK_END aber kein offizielles beispiel wie die form in seek(TEST,0,1); ?!
                  Müsste dies dann in etwa so seek(TEST,0,SEEK_END); aussehen?
                  Grüsse vom
                  Alain

                  1. jetzt gehts so :)

                    sub check
                    {
                    my $zugriff = 0;
                    open(DATEN,"+<$logfile") || Dead();
                    flock(DATEN,LOCK_EX) || die "cannot lock $!\n";
                    while (<DATEN>){
                    $zugriff++ if /$etwas geschriebenes/;
                         }
                         if ($zugriff)
                         {
                         Dead();
                         }
                         seek (DATEN, 0, 2);
                         print DATEN "$etwas geschriebenes\n";
                         close (DATEN) || die "cannot close $!\n";

                    }

                    Ich dachte mir,man könnte z.B. das script direkt sterben lassen indem man z.B.
                    dies schreibt "dead() if /$etwas geschriebenes/;" anstatt $zugriff++ if...
                    aber das geht so nicht,ansosten könnte man dann auch auf den if zweig verzichten.

                    Stimmt, warum geht das nicht?

                    Dead() if /$etwas geschriebenes/;

                    sollte eigentlich funktionieren (wobei ich das Gefühl hab, dass sterben zuviel ist, oder?)

                    Da du mich ja schon nach der 2 gefragt hast, man sollte auch hier die Konstanten aus fnctl verwenden, da die 2 nicht immer SEEK_SET sein muss.

                    nach dem seek in form von fnctl habe ich nur http://www.perldoc.com/perl5.8.0/pod/func/seek.html etwas gesehen von
                    SEEK_END aber kein offizielles beispiel wie die form in seek(TEST,0,1); ?!
                    Müsste dies dann in etwa so seek(TEST,0,SEEK_END); aussehen?

                    oh, stimmt.
                    ich hatte mit den Konstanten auch einige Probleme, da die nicht überall laufen (also fcntl nicht immer exportiert). aber versuchen würd cih's auf jeden Fall:

                    use fcntl qw/:seek :flock/;

                    Struppi.

                    1. hallo struppi,

                      Stimmt, warum geht das nicht?

                      Dead() if /$etwas geschriebenes/;

                      sollte eigentlich funktionieren (wobei ich das Gefühl hab, dass sterben zuviel ist, oder?)

                      tatsächlich es geht,hatte gestern wohl eine { zuviel weggelassen.dead ist doch ein gutes wort
                      und trifft die funktion genau und so soll es auch sein :)

                      Müsste dies dann in etwa so seek(TEST,0,SEEK_END); aussehen?

                      oh, stimmt.
                      ich hatte mit den Konstanten auch einige Probleme, da die nicht überall laufen (also fcntl nicht immer exportiert). aber versuchen würd cih's auf jeden Fall:

                      use fcntl qw/:seek :flock/;

                      denkst Du diese methode ist besser?Weil,wenn Du schon zweifelst an fcntl dann lass ich es lieber mal so wie's ist,denn es funtzt so tadelos.
                      Jedenfalls nochmals besten dank .
                      Grüsse
                      Alain

                      1. ich hatte mit den Konstanten auch einige Probleme, da die nicht überall laufen (also fcntl nicht immer exportiert). aber versuchen würd cih's auf jeden Fall:

                        use fcntl qw/:seek :flock/;

                        denkst Du diese methode ist besser?Weil,wenn Du schon zweifelst an fcntl dann lass ich es lieber mal so wie's ist,denn es funtzt so tadelos.
                        Jedenfalls nochmals besten dank .

                        ich hatte mal irgendwo eine veraltete Version von fcntl, das Problem mit den Werten ist, dass diese nicht auf allen Betriebsystemen gleich sein müssen. Während die Konstanten aus fcntl dem OS angepasst sind.

                        Struppi.

    2. hi Struppi

      /$etwas_geschriebenes/ ? $Zugriffe = $Zugriffe + 1 : $Zugriffe = $Zugriffe;

      Das hatten wir doch letztens erst:

      stimmt und zwar hier [pref:t=57918&m=326789] aber du willst ja nichts mehr lernen :-) *fg* (es kann ja nicht an gehen das ich immer nur von dir lerne)

      Besser so:

      $Zugriffe = /$etwas_geschriebenes/ ? $Zugriffe + 1 : $Zugriffe;

      tztz

      $etwas_geschriebenes ? ($Zugriffe += 1) : ($Zugriffe);

      bis bis roman

      --
      P.S. manchmal wundere ich mich schon über die postings (fragen u. antworten) die man hier geboten bekommt(meine eigenen [leider] mit eingenommen)
      => ich denke mir meinen teil und ziehe das beste daraus :-)
      1. Das hatten wir doch letztens erst:
        stimmt und zwar hier [pref:t=57918&m=326789] aber du willst ja nichts mehr lernen :-) *fg* (es kann ja nicht an gehen das ich immer nur von dir lerne)
        Besser so:

        $Zugriffe = /$etwas_geschriebenes/ ? $Zugriffe + 1 : $Zugriffe;
        tztz

        $etwas_geschriebenes ? ($Zugriffe += 1) : ($Zugriffe);

        Hier ist dieser Operator überflüssig.
        noch einfacher, da er ja bei else eh nichts machen will:

        $Zugriffe++ if /$etwas_geschriebenes/;

        Struppi.