Schrift
[thread]12501[/thread]

Skript nach Programmaufruf fortsetzen

Leser: 2


<< |< 1 2 >| >> 13 Einträge, 2 Seiten
IceRage
 2008-09-16 02:13
#114689 #114689
User since
2008-09-07
93 Artikel
BenutzerIn
[default_avatar]
Hallo allerseits,

angeblich soll ja system() im Gegensatz zu exec(), dass Skript nicht beenden. Vielleicht hab ich ja was falsch gemacht, aber bei mir geht das irgendwie nicht. Ob ich nun system() oder exec() aufrufe, dass Skript läuft erst dann weiter, wenn das Aufgerufene Programm (Firefox), wieder geschlossen wurde (alles unter Debian übrigens).

Folgendes habe ich darauf hin ausprobiert:

Code (perl): (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
while (1) {
        pipe(READER,WRITER);
        READER->autoflush(1);
        WRITER->autoflush(1);

        my $pid = fork();

        if($pid == 0){
                # Child-Prozess
        
                close READER;
                print WRITER $$;
                print "Ich bin das Kind:  ",$$,"\n";
                my $output = system("/usr/bin/firefox file:///home/uname/log/testseite.html");
                # print $output;                
                exit(0);
        }
        else{
                # Parent-Prozess
                print "Ich bin der Vater: ",$$,"\n";
                wait();

                close WRITER;

                my $i = 0;

                my @line = <READER>;
                while (1) {
                        print "$i Ich bin der Vater: ",$$,"\n";
                        print "$i Und mein Kind ist: ",$line[0],"\n";
                        $i++;
                        sleep(1);
                        if ($i >= 5) {
                                $i = 0;
                                exit(0);
                                # Child killen !
                        }
                }
        }
        print "besser dann doch abbrechen.";
        sleep(1);
}



Das Sktipt soll Folgendes tun:

- 1. Browser öffnen
- 2. In die while schleife (Parent Prozess) gehen
- 3. Nach 20 Schleifendurchläufen (Parent Prozess) den Browser, an Hand der übermittelten PID schließen.
- 4. Dann wieder das Selbe ... 1.

Ich bekomm das nicht hin. Kann mir dabei bitte jemand helfen?

Gruß, IceRage
moritz
 2008-09-16 02:20
#114690 #114690
User since
2007-05-11
923 Artikel
HausmeisterIn
[Homepage]
user image
Quote
Code: (dl )
my $output = system("/usr/bin/firefox file:///home/uname/log/testseite.html");


Ich glaube, du willst firefox im Hintergrund starten, also system '/usr/bin/firefox file:///home/uname/log/testseite.html &';. Ausserdem liefert system() nicht die Ausgabe, sondern einen durch die Mangel gedrehten return-code.
murphy
 2008-09-16 02:55
#114691 #114691
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
@IceRage: Wenn man explizit wait aufruft, darf man sich nicht wundern, dass der Elternprozess auf seine Kinder wartet, bevor er weiter läuft.

@moritz: Da vor dem system aufruf geforkt wird, ist es eigentlich keinesfalls nötig, mit einem & die Shell anzuweisen, den Prozess in den Hintegrund zu stellen.

Wenn man in diesem einfachen Anwendungsfall selber forkt, könnte man aber statt system sicherer und resourcenschonender exec verwenden. Wenn man system nehmen will, könnte man sich das forken sparen und, wie moritz schreibt, den Befehl durch die Shell in den Hintergrund stellen lassen.

Am besten ist es aber wahrscheinlich, etwas wie CPAN:Proc::SafeExec zu verwenden.
When C++ is your hammer, every problem looks like your thumb.
IceRage
 2008-09-16 11:00
#114694 #114694
User since
2008-09-07
93 Artikel
BenutzerIn
[default_avatar]
Hallo, und vielen Dank erstmal für die Rückmeldungen.


murphy+2008-09-16 00:55:26--
@IceRage: Wenn man explizit wait aufruft, darf man sich nicht wundern, dass der Elternprozess auf seine Kinder wartet, bevor er weiter läuft.

Also ich habe das wait() jetzt mal rausgenommen, der Eltern Prozess läuft aber leider dennoch nicht an. Erst wenn dich das aufgerufene Programm beendet habe.


murphy+2008-09-16 00:55:26--
@moritz: Da vor dem system aufruf geforkt wird, ist es eigentlich keinesfalls nötig, mit einem & die Shell anzuweisen, den Prozess in den Hintegrund zu stellen.

Wenn ich das Ampersand an die richtige Stelle setze, läuft das Skript wie gewünscht ab. Das ist schon mal ein Fortschritt ;-)


murphy+2008-09-16 00:55:26--
Wenn man in diesem einfachen Anwendungsfall selber forkt, könnte man aber statt system sicherer und resourcenschonender exec verwenden. Wenn man system nehmen will, könnte man sich das forken sparen und, wie moritz schreibt, den Befehl durch die Shell in den Hintergrund stellen lassen.

Das werde ich mal so machen denke ich. Scheint genau das dabei heraus zu kommen, was ich brauche.


murphy+2008-09-16 00:55:26--
Am besten ist es aber wahrscheinlich, etwas wie CPAN:Proc::SafeExec zu verwenden.

Thx, für den Tipp. Schau ich mir mal an.



Mir ist noch etwas Anderes aufgefallen. Wenn ich mir mal den Rückgabewert vom READER anschaue, also die PID die bei:

Code (perl): (dl )
my @line = <READER>;


ausgelesen wird, dann ist der immer exakt um den Betrag 2 zu gering, im Vergleich zu einer Ausgabe mit ps -aux | grep firefox. Das ist wirklich immer so. Weil das so ist, ist es ja nicht weiter schlimm. Ich kann ja immer den Betrag 2 hinzu addieren. Aber ich finde das schon recht merkwürdig und eigentlich auch nicht wirklich sicher ... vielleicht unterscheiden sich die Werte dann doch mal um 3, oder 1 und nicht um 2.


Gruß, IceRage
murphy
 2008-09-16 11:25
#114695 #114695
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
IceRage+2008-09-16 09:00:41--
murphy+2008-09-16 00:55:26--
@IceRage: Wenn man explizit wait aufruft, darf man sich nicht wundern, dass der Elternprozess auf seine Kinder wartet, bevor er weiter läuft.

Also ich habe das wait() jetzt mal rausgenommen, der Eltern Prozess läuft aber leider dennoch nicht an. Erst wenn dich das aufgerufene Programm beendet habe.
[...]


Vor dem Eintritt Deines Elternprozesses in die Endlosschleife liest Du aus einer Pipe Daten mittels
Code (perl): (dl )
my @line = <READER>;

ein. Da du hier readline im Arraykontext verwendest, werden solange weitere Zeilen aus der Pipe gelesen, bis das Dateiende erreicht ist – das ist bei einer Pipe aber erst dann der Fall, wenn ihr anderes Ende geschlossen wurde, was Dein Kindprozess niemals tut. Die Pipe wird also erst implizit vom Systemkern geschlossen, wenn der Kindprozess stirbt und erst zu diesem Zeitpunkt wird der readline-Aufruf im Elternprozess zurückkehren.

Quote
[...]
Mir ist noch etwas Anderes aufgefallen. Wenn ich mir mal den Rückgabewert vom READER anschaue, also die PID die bei:

Code (perl): (dl )
my @line = <READER>;


ausgelesen wird, dann ist der immer exakt um den Betrag 2 zu gering, im Vergleich zu einer Ausgabe mit ps -aux | grep firefox.
[...]


Logisch, was Du da in die Pipe schreibst ist ja auch nicht die Prozessid von Firefox, sondern die von Deinem Kindprozess. So wie Dein Programm strukturiert ist, wird hier aber dreimal geforkt:

(1) Dein Programm forkt explizit.
(2) Perl forkt implizit in der Funktion system, um die Shell zu starten, ohne sich selbst zu beenden.
(3) Die Shell forkt implizit, um Firefox zu starten, ohne sich selbst zu beenden.

In vielen Systemen wird die Prozessid neuer Prozesse bei jedem Fork einfach durch das Erhöhen eines globalen Zählers generiert, was Du hier beobachtest.

Manche Systeme generieren aus Sicherheitsgründen völlig zufällige Prozessids. Irgendwelche Arithmetik mit Prozessids durchzuführen ist also unportabel und gefährlich.

Abgesehen davon müsstest Du eigentlich die Prozessid Deines Kindes nicht so schrecklich kompliziert ermitteln, sondern lediglich den Rückgabewert von fork benutzen, den Du ja sowieso speicherst...
When C++ is your hammer, every problem looks like your thumb.
murphy
 2008-09-16 11:43
#114696 #114696
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
IceRage+2008-09-16 00:13:48--
[...]
Das Sktipt soll Folgendes tun:

- 1. Browser öffnen
- 2. In die while schleife (Parent Prozess) gehen
- 3. Nach 20 Schleifendurchläufen (Parent Prozess) den Browser, an Hand der übermittelten PID schließen.
- 4. Dann wieder das Selbe ... 1.
[...]


Also nochmal zum Kern des Problemes. Ich würde folgendes machen:
Code (perl): (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
use strict;
use warnings;
use POSIX;
use constant TIMEOUT => 20;

my $firefox;
unless ($firefox = fork) {
  die "Failed to fork: $!" unless (defined $firefox);
  exec '/woimmer/ich/bin/firefox', 'http://www.example.com/';
  die "Failed to spawn firefox: $!";
}
else {
  # remember time the browser was started
  my $start = time;
  my $remaining = TIMEOUT;

  # only loop while the browser is still running and the timeout is not over
  while (waitpid($firefox, WNOHANG) < 0 and $remaining > 0) {
    sleep $remaining;
    $remaining = $start + TIMEOUT - time;
  }

  # send the browser a TERM signal
  kill TERM => $firefox;
  # clean up the zombie process
  die "Problems cleaning up the browser process: $!" if (waitpid($firefox, 0) < 0);
}

(Vorsicht: Code ungetestet!)

Anmerkung: Falls Du eigentlich nur alle paar Sekunden eine neue Webseite anzeigen willst, musst Du den Browser, den Du startest, nicht wieder beenden. Suche mal im Netz nach firefox -remote 'openURL(...)'...
When C++ is your hammer, every problem looks like your thumb.
Gast Gast
 2008-09-16 14:17
#114699 #114699
1. "wait" wartet auf das beenden aller prozesse. Du brauchst "waitpid"

2. "exit" im eletrnprozess beendet ihn. Wenm du das kind beendet willst mußt du "kill" benutzen.

3. warum nutzt du eine Pipe wenn du es auch so machen kannst:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
unless(open(READ '-|')){
while(1){
print STDOUT "kind\n";
sleep(1);
}
}else{
sleep(5);
my @child=<READ>;
print "@child";
close(READ);
}
exit();
nepos
 2008-09-16 14:59
#114700 #114700
User since
2005-08-17
1420 Artikel
BenutzerIn
[Homepage] [default_avatar]
Gast+2008-09-16 12:17:28--
1. "wait" wartet auf das beenden aller prozesse. Du brauchst "waitpid"


Nein, wait wartet auf den ersten Kind-Prozess, der sich beendet. Nicht auf alle.
Btw, in perlipc gibts dazu auch ein wenig nachzulesen.
murphy
 2008-09-16 16:28
#114708 #114708
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Gast+2008-09-16 12:17:28--
[...]
3. warum nutzt du eine Pipe wenn du es auch so machen kannst:
Code: (dl )
unless(open(READ '-|')){

[...]


Auch dieser Code erstellt eine Pipe und ist folglich völlig äquivalent zu dem des OP.
When C++ is your hammer, every problem looks like your thumb.
IceRage
 2008-09-28 04:01
#114994 #114994
User since
2008-09-07
93 Artikel
BenutzerIn
[default_avatar]
Hallo,

sorry das ich deswegen noch mal nachfrage. Aber ich habe jetzt alles mir mögliche ausprobiert, und es haut einfach nicht so hin, wie es soll. Das Problem ist, dass, egal wie ich firefox aufrufe, einfach der kindprozess nicht weiter abgearbeitet wird. Ich habe versucht firefox mit exec und system in den Hintergrund zu legen, ich habe versucht mit backticks, mit und ohne Rückgabewerte zu arbeiten ... nichts funktioniert.

Der Gedanke ist, dass der Elternprozess auf den Kindprozess warten soll, und der Kindprozess sich nach 35 sekunden, mit einem exit(0) beendet (und damit auch das Browserfenster geschlossen wird). Warum jetzt aber der Kindprozess trotz des Aufrufs mittels system() nicht weiter arbeitet, will mir einfach nicht in den Kopf. Ich will jetzt hier keinen Glaubenskrieg der Betriebssysteme entfachen, aber unter window$ funktioniert das ganz einfach mit: system("/usr/bin/firefox test.html"); .. warum geht das mit meinem Debian nicht? ... raff ich nicht.


Code (perl): (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
#!/usr/bin/perl

use POSIX;
use warnings;
use strict;

my $file = "lines.txt";
open(LINES, "<$file");

my @ar_lines = <LINES>;
print $ar_lines[0]."\n";
foreach my $link (@ar_lines) {
        print $link."\n";
        my $pid = fork();

        if($pid == 0){
                # Child-Prozess 
                print "Ich bin das Kind:  ",$$,"\n";

                # hier zu öffnender link, klappt alles nicht, auch nicht mit Backticks
                # my $ret_val = system("/usr/bin/firefox $link");
                # my $ret_val = exec("/usr/bin/firefox $link");
                # my $ret_val = `/usr/bin/firefox $link &`;
                # my $ret_val = system("/usr/bin/firefox $link &");
                system("/usr/bin/firefox test.html");

                sleep(35);
                exit(0);
        } else {
                # Parent-Prozess
                print "Ich bin der Vater: ",$$,"\n";    
                waitpid($pid, 0);

                print "Ich bin der Vater: ",$$,"\n";
                print "Und mein Kind ist: ",$pid,"\n";
        }
        sleep(20);
}



Das Browserfenster möchte ich schließen, weil sonst, wenn ich das Skript morgens starte, am Abend 100 Seiten geöffnet sein könnten. Und da das Skript auf einem alten Rechner läuft, würde da der Arbeitsspeicher für die übrigen Programme nicht mehr ausreichen (512MB). Wäre echt nett, wenn mir dabei noch mal jemand helfen könnte.

Vielen Dank. IceRage
<< |< 1 2 >| >> 13 Einträge, 2 Seiten



View all threads created 2008-09-16 02:13.