Perl/Funktionen für Betriebssystemaufrufe

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

[Bearbeiten] Allgemeines zu diesen Funktionen

Unter "Betriebssystemaufrufe" sind hier Funktionen versammelt, die sich vor allem eng am Konzept der Unix-Betriebssysteme orientieren. Nur wenige der Funktionen sind auf andere Systeme portierbar.

Unix-Systeme verwalten laufende "Programme" in so genannten Prozessen. Jeder Prozess hat eine Prozessnummer (PID). Außerdem gibt es Prozessgruppen. Jeder Prozess gehört zu einer Prozessgruppe. Prozessgruppen haben ebenfalls Nummern. Auch Ihr Perl-Script stellt, wenn es ausgeführt wird, einen solchen Prozess dar, der einer Prozessgruppe angehört. Bei vielen der hier beschriebenen Funktionen können Sie den aktuellen Prozess, also den Ihres Perl-Scripts, durch die "virtuelle" Prozessnummer 0 ansprechen. Über vordefinierte Variablen können Sie jedoch auch die tatsächliche Prozessnummer herausfinden und benutzen. Das folgende Beispielscript zeigt die entsprechenden Variablen im Einsatz:

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
print "Prozessnummer (PID): <strong>$$</strong><br>\n";
print "Reale Benutzergruppe (GID) des Prozesses: <strong>$(</strong><br>\n";
print "Effektive Benutzergruppe (GID) des Prozesses: <strong>$)</strong>\n";
print "</body></html>\n";
Mit $$ sprechen Sie die Nummer des aktuellen Prozesses an. Der Prozess läuft unter einer bestimmten User-ID, die wiederum einer oder mehreren Gruppen angehört. Wenn das Script beispielsweise mit setgid gestartet wurde, enthält die reale Gruppen-ID die Gruppe(n), von der aus gestartet wurde, die effektive Gruppen-ID enthält die Gruppe(n), in die gewechselt wurde (die aktuelle also). Das Beispiel-CGI-Script gibt die entsprechenden Daten aus. Weitere wichtige Konzepte der Unix-Betriebssysteme, auf die Sie mit Perl-Funktionen Zugriff haben, sind Alarme, Kindprozesse und die so genannten Pipes. Nähere Informationen dazu finden Sie in der Unix-Fachliteratur.

[Bearbeiten] qx(...) - Andere Programme/Scripts ausführen und STDOUT auffangen

Hierbei handelt es sich eigentlich nicht um eine Perl-Funktion, sondern um eine besondere Form des Notierens von Zeichenketten. Das qx steht für quoted executable. Die darin eingeschlossene Zeichenkette wird von Perl einfach in einen Kommandozeilenaufruf umgesetzt. Die Standardausgabe des aufgerufenen Kommandos, Fremdprogramms oder Scripts wird aufgefangen und kann in einer Variablen gespeichert werden. Eine andere Möglichkeit, diese Art von ausführbaren Zeichenketten zu notieren, sind die so genannten Backticks. Dabei arbeiten Sie anstelle von qx(irgendein Kommando) mit dem rückwärts gerichteten Accent-Zeichen ` und notieren `irgendein Kommando`.

Die Funktionalität der ausführbaren Zeichenketten ist für CGI-Scripts extrem nützlich, um die Ausgaben anderer Prozesse auffangen und an den Browser senden lassen zu können. So lassen sich beispielsweise XML-Daten mit XSLT und einem XSLT-Prozessor in HTML übersetzen. Wenn dieser Prozessor seine Ergebnisse auf den Standardausgabekanal STDOUT schreibt, kann das CGI-Script die Ausgabe auffangen und an den Webserver zur Weiterleitung übergeben. Das folgende Beispiel zeigt dies.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
my $Output = qx(/usr/bin/saxon /daten/xml/kunden.xml /daten/xml/kunden.xsl);
print "$Output";
Mehr als dieses winzige Script ist nicht nötig, um XML-Daten in HTML-Form an den Webserver zur Übergabe an einen aufrufenden Browser zu senden - sofern ein XSLT-Prozessor die Übersetzungsarbeit leistet. Das Beispiel führt folgendes Kommando aus:

/usr/bin/saxon /daten/xml/kunden.xml /daten/xml/kunden.xsl

Dabei ist saxon der Name eines XSLT-Prozessors, also eines ausführbaren Programms. Dieses Programm erwartet im Normalfall zwei Aufrufparameter: erstens die Angabe einer XML-Datei, und zweitens die Angabe einer dazu passenden XSL-Datei mit XSLT-Anweisungen. Saxon übersetzt die XML-Auszeichnungen aufgrund der XSLT-Angaben in HTML-Konstrukte und gibt das Ergebnis, eine vollständige HTML-Datei, auf die Standardausgabe aus. Das Script fängt diese Standardausgabe auf, indem es sie in der Variablen $Output speichert. In dieser Variablen steht also nach dem Saxon-Aufruf der gesamte Inhalt der HTML-Daten. Ein einfacher print-Befehl genügt anschließend, um die gesamten HTML-Daten auszugeben.
Beachten Sie: Die Art der Klammerung bei Verwendung von qx ist egal. Sie können auch eckige oder geschweifte Klammern oder Schrägstriche verwenden - von letzteren ist allerdings abzuraten, weil viele Kommandos Pfadangaben benötigen und Sie in diesem Fall alle Schrägstriche bei Pfadangaben maskieren müssten.

Bei Pfadangaben sollten Sie auch bei qx(...) stets die einfachen Schrägstriche verwenden - auch wenn das Perl-Script unter Windows ausgeführt wird.

Mit Backticks würde der Aufruf des obigen Beispiels lauten:
my $Output = `/usr/bin/saxon /daten/xml/kunden.xml /daten/xml/kunden.xsl`;
Um die Backticks zu erzeugen, halten Sie auf den meisten Systemen die Shift-Taste gedrückt, tippen einmal auf die Taste mit den französischen Accent-Zeichen und anschließend die Leertaste.

Im Link-Verzeichnis des Online-Angebots von SELFHTML aktuell finden Sie Links zu XML-Software. Dort finden Sie ebenso Verweise zu Produkten wie Saxon.

Die hier beschriebene Möglichkeit ist auf alle Kommandos anwendbar, die etwas auf die Standardausgabe STDOUT schreiben, also z.B. auch auf Betriebssystem-Kommandos wie ls (bzw. dir), oder auch auf andere Perl-Scripts. Einige solcher Programme oder Kommandos schreiben ihren Output bei fehlerhaften Aufrufen jedoch nicht auf STDOUT, sondern auf STDERR. Solche Ausgaben werden von den hier beschriebenen ausführbaren Zeichenketten nicht aufgefangen.

[Bearbeiten] alarm - SIGALARM in n Sekunden zustellen

Unix-spezifischer Befehl. Bewirkt, dass der Prozess einen SIGALARM nach einer bestimmten Anzahl Sekunden erhält, wenn z.B. ein kritischer Befehl nicht funktioniert.

Erwartet als Parameter:

  1. die Anzahl Sekunden, bis der Alarm aktiv wird.

Gibt die Anzahl Sekunden zurück, die verstrichen sind.

Beispiel
#!/usr/bin/perl -w
 
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body><pre>\n";
 
eval {
  local $SIG{ALRM} = sub { die "Alarm" };
  alarm(2);
  system("/usr/bin/perl -c /usr/web/myhome/cgi-bin/freelink.pl");
  alarm(0);
};
if ($@ and $@ !~ /Alarm/) {
  print "Problem! 2 Sekunden vergangen!\n";
}
else {
  print "Alles klar!\n";
}
print "</pre></body></html>\n";
Das Beispiel zeigt, wie Sie einen "kritischen Systemaufruf" mit Hilfe eines Timeout-Alarms behandeln können. Dazu wird in dem Script zunächst ein für solche Behandlung typischer eval-Block notiert. Darin wird mit der typischen Anweisung:

local $SIG{ALRM} = sub { die "Alarm" };
eine Behandlungsroutine für SIGALARM definiert. Anschließend wird mit alarm(2) ein Timeout von 2 Sekunden definiert, bevor der Alarm aktiv wird. Mit alarm(0) wird der Alarm wieder zurückgesetzt.
Danach wird versucht, mit system den Perl-Interpreter aufzurufen, und zwar so, dass er ein bestimmtes Script auf die Gültigkeit seiner Syntax überprüft. Sollte dieser Vorgang mehr als 2 Sekunden dauern, wird der Alarm aktiv.

Mit der Abfrage if ($@ and $@ !~ /Alarm/) wird überprüft, ob der Alarm aktiv wurde. Wenn ja, wird eine entsprechende Meldung ausgegeben. Im else-Zweig kann der Code stehen, der ausgeführt wird, wenn alles in Ordnung war. Im Beispiel wird einfach ebenfalls eine entsprechende Meldung ausgegeben.
Beachten Sie: Aufrufe mit system oder qx(...) in Verbindung mit alarm können zu sogenannten Zombies führen. Möglicherweise müssen Sie sie für solche Zwecke mit Hilfe von fork und exec selbst implementieren.

[Bearbeiten] exec - Fremdprogramm aufrufen und eigenen Prozess beenden

Startet einen anderen Prozess und beendet das aktuelle Script. Der aktuelle Prozess wird dabei durch den neuen Prozess vollständig ersetzt. Wenn Sie das aktuelle Script nicht beenden wollen, benutzen Sie system, qx(...) oder open mit dem Pipe-Zeichen |.

Erwartet als Parameter:

  1. Kommandozeilenaufruf des gewünschten Programms,
  2. bis n. (optional) Liste mit Aufrufparametern.
Beispiel
#!/usr/bin/perl -w
 
exec("/usr/bin/perl","mystats.pl") if -e "mystats.pl";
Das Beispiel fragt mit Hilfe des [[Perl/Funktionen für Datei- und Verzeichnis-Management#-[x]|Dateitestoperators]] -e ab, ob eine Datei namens mystats.pl im aktuellen Verzeichnis existiert. Wenn ja, wird der Perl-Interpreter (in einem eigenen neuen Prozess) gestartet und führt mystats.pl aus.

[Bearbeiten] fork - Kindprozess erzeugen

Unix-spezifischer Befehl. Erzeugt eine Kopie des aktuellen Prozesses, die dem aktuellen erzeugenden Prozess untergeordnet ist. Ein Perl-Script kann sich auf diese Weise gabeln (engl. fork) und Daten in zwei getrennten Prozessen verarbeiten. Auf geöffnete Dateien können dabei beide Prozesse zugreifen. Alles übrige, wie Variablen usw., wird vom Elternprozess in den Kindprozess kopiert. Die Variable, die den Rückgabewert von fork speichert, hat jedoch im Elternprozess einen Wert, nämlich die Prozessnummer des Kindprozesses, während sie im Kindprozess den Wert 0 hat.
Obwohl fork eigentlich aus der Unix-Welt stammt, lässt sich diese Funktion mittlerweile auch unter ActivePerl für Windows nutzen.

Erwartet keine Parameter.

Gibt die vom Betriebssystem zugewiesene Prozessnummer des Kindprozesses zurück.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
$| = 1;
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
my $Eltern_pid = $$;
my $Kind_pid = fork();
 
if($Kind_pid) {
  print "<p>Hier ist der Elternprozess. Der Kindprozess hat die PID <strong>$Kind_pid</strong></p>\n";
  wait;
}
else {
  my $Eltern_pid = getppid();
  print "<p>Hier ist der Kindprozess. Der Elternprozess hat die PID <strong>$Eltern_pid</strong></p>\n";
  exit(0);
}
print "</body></html>\n";
Das Beispiel erzeugt mit fork einen Kindprozess. Der Rückgabewert der Funktion, die Prozessnummer des Kindprozesses, wird in dem Skalar $Kind_pid gespeichert. Im Beispiel ist daraufhin eine if-Abfrage notiert. Mit if($Kind_pid) wird abgefragt, ob der Skalar $Kind_pid einen Wert ungleich 0 hat. Ist das der Fall, werden Anweisungen ausgeführt, die zum Elternprozess gehören. Im Beispiel wird eine Meldung ausgegeben, dass sich das Script im Elternprozess befindet. Außerdem wird die Prozessnummer des Kindprozesses ausgegeben. Danach wird mit der Anweisung wait gewartet, bis der Kindprozess beendet ist. Im else-Zweig, in den das Script gelangt, wenn Kind_pid den Wert 0 hat, wird dagegen ausgegeben, dass der Kindprozess aktiv ist. Außerdem wird die Prozessnummer des Elternprozesses ausgegeben. Danach wird der Kindprozess mit der Anweisung exit(0); beendet. Der Elternprozess, der darauf nur gewartet hat, gibt dann noch die letzte Zeile HTML-Code aus.
Das besondere Verhalten des Scripts, das in zwei Prozessen läuft, zeigt sich im Beispiel darin, dass sowohl der if-Zweig als auch der else-Zweig ausgeführt werden. Das erklärt sich daraus, dass die if-Bedingung für den Elternprozess wahr ist, die else-Alternative dagegen für den Kindprozess.

[Bearbeiten] getpgrp - Prozessgruppe einer Prozessnummer (pid) ermitteln

Unix-spezifischer Befehl.

Erwartet als Parameter:

  1. eine Prozessnummer, zu der die zugehörige Prozessgruppe ermittelt werden soll. Um die Prozessgruppe des aktuellen Prozesses zu ermitteln, müssen Sie 0 übergeben.

Gibt die Gruppennummer zurück.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
 
my $Gruppennummer = getpgrp(0);
print "Die Prozessgruppe des aktuellen Prozesses ist <strong>$Gruppennummer</strong>\n";
 
print "</body></html>\n";
Das Beispiel ermittelt die Gruppennummer des aktuellen Prozesses mit getpgrp und gibt HTML-Code mit der ermittelten Nummer aus.

[Bearbeiten] getppid - Prozessnummer (pid) des Elternprozesses ermitteln

Unix-spezifischer Befehl.

Erwartet keine Parameter.

Gibt die Prozessnummer (PID) des Elternprozesses des aktuellen Scripts zurück.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
 
my $Eltern_pid = getppid();
print "Die PID des Elternprozesses lautet <strong>$Eltern_pid</strong>\n";
 
print "</body></html>\n";
Das Beispiel ermittelt die PID des Elternprozesses mit getppid und gibt HTML-Code mit der ermittelten Nummer aus.

[Bearbeiten] getpriority - Text

Unix-spezifischer Befehl. Ermittelt die aktuelle Priorität eines Prozesses, einer Prozessgruppe oder eines Benutzers. Prozesse mit höherer Priorität erhalten unter den aktuell laufenden Prozessen mehr Systemressourcen zur Ausführung.

Erwartet als Parameter:

  1. eine Angabe dazu, ob Sie die Priorität für einen bestimmten Prozess, eine Prozessgruppe oder einen Benutzer ermitteln wollen. Dazu übergeben Sie am besten eine der Konstanten, die in resource.ph definiert sind (siehe unten).
  2. die Nummer des Prozesses, der Prozessgruppe oder des Benutzers.

Gibt die Priorität des Prozesses, der Prozessgruppe oder des Benutzers als Zahl zurück. Der mögliche Wertebereich ist abhängig vom System.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
 
require "resource.ph";
my $Prio = getpriority(&PRIO_PROCESS,0);
print "Prioritaet des aktuellen Prozesses: $Prio\n";
 
print "</body></html>\n";
Das Beispiel ermittelt mit getpriority die Priorität des aktuellen Prozesses und gibt diese aus. Dazu wird mit require "resource.ph" die Kopfdatei eingebunden, die die Definition der folgenden Konstanten enthält:
Konstante: Bedeutung:
PRIO_PROCESS Die Priorität eines bestimmten Prozesses ermitteln, dessen Prozessnummer (oder 0 für den aktuellen Prozess) im zweiten Parameter von getpriority angegeben wird.
PRIO_PGRP Die Priorität einer Prozessgruppe ermitteln, deren Nummer (oder 0 für die aktuelle Prozessgruppe) im zweiten Parameter angegeben wird.
PRIO_USER Die Priorität eines Benutzers ermitteln, dessen Benutzernummer (UID - oder 0 für den aktuelle Benutzer) im zweiten Parameter angegeben wird.
Durch Voranstellen eines &-Zeichens können Sie eine der Konstanten wie im Beispiel gezeigt als ersten Parameter übergeben.
Beachten Sie: Diese Funktion führt zu einem schweren Fehler, wenn das System keine Prozess- bzw. Benutzerverwaltung im Sinne von Unix kennt.

[Bearbeiten] kill - Signal an Prozess senden

Unix-spezifischer Befehl. Damit können Sie aus einem Perl-Script heraus Signale an andere laufende Prozesse auf dem Rechner senden und diese dadurch beeinflussen. Interessant ist dies vor allem, wenn Sie in Ihrem Perl-Script eigene Kindprozesse erzeugen (siehe fork). Eltern- und Kindprozess können dann durch Signale kommunizieren.

Erwartet als Parameter:

  1. Nummer oder Name einer Konstante (siehe Tabelle weiter unten) des gewünschten Signals (oder Sie übergeben 0, um herauszufinden, ob der Prozess mit der nachfolgend übergebenen Prozessnummer noch "am Leben" ist),
  2. bis n. einer oder mehrere Prozesse, an die das Signal gesendet werden soll.
Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
$| = 1;
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
 
my $Kind_pid = fork();
 
if(kill(0,$Kind_pid)) {
  print "<p>Hier meldet sich ein Prozess</p>\n";
  kill("KILL",$Kind_pid);
}
print "</body></html>\n";
Das Beispiel erzeugt mit fork einen Kindprozess. Mit if(kill(0,$Kind_pid)) wird abgefragt, ob dieser Prozess am Leben ist. Wenn ja, wird ausgegeben, dass sich ein Prozess meldet. Da im Beispiel für den Kindprozess kein eigener Perl-Code notiert ist und Kindprozesse einfach erst mal alles vom Elternprozess kopieren, würden beide Prozesse sich melden und Hier meldet sich ein Prozess ausgeben. Doch im Beispiel wird das verhindert, indem der Elternprozess den Kindprozess mit kill("KILL",$Kind_pid) tötet, bevor dieser die Anweisung mit der Ausgabe der Meldung ausführen kann. Die Meldung wird also insgesamt nur einmal ausgegeben.

Die folgende Tabelle enthält typische Signale mit Namen, wie Sie sie als ersten Parameter an kill übergeben können. Eine Garantie, dass alle hier aufgelisteten Signale auf jedem Rechner in Perl funktionieren, besteht nicht. Auch die entsprechenden Nummern wurden hier weggelassen, da sie von System zu System schwanken können. Maßgeblich ist letztendlich immer, was auf dem jeweiligen Rechner in der Datei /usr/include/signal.h definiert ist.

Name: Bedeutung:
"HUP" Ereignis: Verbindung beendet
"INT" Ereignis: allgemeine Unterbrechung
"QUIT" Ereignis: Endekennzeichen
"ILL" Anweisung ist illegal
"TRAP" Anweisung ist eine "Falle"
"ABRT" Abbruch
"FPE" Fehler bei Fließkommaberechnung
"KILL" Prozess "abschießen" (Unix: kill -9)
"BUS" Bus-Übertragungsfehler
"SEGV" Segment-Schutzverletzung im Speicher
"PIPE" Fehler bei Pipe-Kommunikation
"ALARM" Allgemeiner Alarm
"TERM" Beendigung
"USR1" Benutzerdefiniert 1
"USR2" Benutzerdefiniert 2
"CHLD" Signal vom Kindprozess
"PWR" Stromausfall
"WINCH" Fenstergröße wurde von einem Hintergrundprozess geändert
"URG" Dringende Bedingung
"IO" Asynchrone Ein-/Ausgabe
"STOP" Prozess anhalten
"TSTP" Prozess vom Terminal aus anhalten
"CONT" Angehaltenen Prozess fortführen
"TTIN" Prozess anhalten durch Lesen vom kontrollierenden Terminal
"TTOU" Prozess anhalten durch Schreiben auf kontrollierendes Terminal
"VTALARM" Virtueller Zeittaktgeber abgelaufen
"PROF" Profil-Zeittaktgeber abgelaufen
"XCPU" CPU-Belastungsgrenze erreicht
"XSFZ" Dateigrößengrenze erreicht
Beachten Sie: Mit dem folgenden Script können Sie abfragen, welche Signale unter welchen Signalnummern auf Ihrem Server-Rechner konfiguriert sind:
#!/usr/bin/perl
 
use Config;
 
defined $Config{sig_name} || die "Kein Konfigmodul?";
foreach $name (split(' ', $Config{sig_name})) {
  $i++;
  printf "%3d) %s \t", $i, $name;
  if (($i % 5) == 0) { print "\n";  }
}
print "\n";

[Bearbeiten] pipe - Pipe erzeugen

Unix-spezifischer Befehl. Ermöglicht zwei Prozessen, miteinander zu kommunizieren. Eine "Pipe" (Pfeife, Röhre) ist dabei der Kommunikationskanal für die beiden Prozesse. Es gibt einen Kanal zum Schreiben von Daten und einen zum Lesen von Daten. Für beide Kanäle gibt es jeweils ein "Handle". Diese Lese- und Schreib-Handles sind ganz ähnlich den Datei-Handles. Typischerweise wird eine Pipe eröffnet, bevor mit fork ein Kindprozess erzeugt wird. Eltern- und Kindprozess können dann über die geöffnete Pipe Daten austauschen.

Erwartet als Parameter:

  1. den Namen eines Lese-Handles (frei vergebbar),
  2. den Namen eines Schreib-Handles (frei vergebbar)
Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
$| = 1;
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body><pre>\n";
 
pipe(LESE_HANDLE, SCHREIB_HANDLE);
my $Kind_pid = fork();
 
if ($Kind_pid) {
 close(LESE_HANDLE);
 my $old_handle = select(SCHREIB_HANDLE);
 $| = 1;
 for (my $i=1;$i<=5;$i++) {
   sleep(1);
   print SCHREIB_HANDLE "$i (gesendet vom Elternprozess)\n";
 }
 close(SCHREIB_HANDLE);
 wait;
 select($old_handle);
}
else {
 close(SCHREIB_HANDLE);
my $Speicher;
 while(defined($Speicher = <LESE_HANDLE>)) {
   print "Empfangen: $Speicher \n";
 }
 exit(0);
}
print "</pre></body></html>\n";
Das Beispiel erzeugt mit pipe eine Pipe. Über die beiden übergebenen Handle-Namen LESE_HANDLE und SCHREIB_HANDLE ist anschließend der Nachrichtenaustausch zwischen zwei Prozessen möglich. Mit Hilfe von fork erzeugt das Script einen Kindprozess. Der Elternprozess läuft im if-Zweig des nachfolgenden Codes, der Kindprozess im else-Zweig. Beim Erzeugen des Kindprozesses wird alles kopiert - außer den beiden Handles aus der Pipe. Diese werden nicht kopiert, bleiben allerdings für beide Prozesse verfügbar. Deshalb muss jeder Prozess erst mal das nicht benötigte Handle mit close schließen. Um die Pufferung der Daten abschalten zu können, muss im if-Zweig außerdem mit select das Schreib-Handle ausgewählt werden. Alle Anweisungen sowohl des if- als auch des else-Zweiges werden insgesamt fünf mal ausgeführt. Denn in einer for-Schleife, die von 1 bis 5 zählt, schreibt der Elternprozess, nachdem er zu Testzwecken eine Sekunde lang anhält (siehe sleep), den aktuellen Zählerstand in das Schreib-Handle. Der Kindprozess im else-Zweig kann diese Daten lesen, indem er eine while-Schleife verwendet und darin das Lese-Handle ausliest. Zur Kontrolle gibt der Kindprozess aus, was er eingelesen hat.

[Bearbeiten] setpgrp - Prozessgruppe für Prozess bestimmen

Unix-spezifischer Befehl. Ordnet einen Prozess einer Prozessgruppe zu.

Erwartet als Parameter:

  1. die Prozessnummer (PID) des gewünschten Prozesses (0 für aktuellen Prozess übergeben),
  2. die Nummer der Prozessgruppe, der dieser Prozess zugeordnet werden soll (0 für aktuelle Prozessgruppe übergeben).
Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
my $gruppe_alt = getpgrp(0);
print "Prozessgruppe alt: <strong>$gruppe_alt</strong><br>\n";
 
setpgrp(0,0);
 
my $gruppe_neu = getpgrp(0);
print "Prozessgruppe neu: <strong>$gruppe_neu</strong>\n";
 
print "</body></html>\n";
Das Beispiel ordnet den aktuellen Prozess der aktuellen Prozessgruppe zu und erzeugt so seine eigene Prozessgruppe. Zum Vergleich wird die aktuelle Prozessgruppe vorher und hinterher ausgelesen und jeweils ausgegeben.

[Bearbeiten] setpriority - Priorität eines Prozesses oder Benutzers setzen

Unix-spezifischer Befehl. Setzt die aktuelle Priorität eines Prozesses, einer Prozessgruppe oder eines Benutzers. Prozesse mit höherer Priorität erhalten unter den aktuell laufenden Prozessen mehr Systemressourcen zur Ausführung.
Da diese Funktion "systemkritisch" ist, steht sie auf den meisten Unix-Systemen nur Benutzern mit root-Kennung zur Verfügung.

Parameter wie bei getpriority

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
 
require "resource.ph";
my $Prio = getpriority(&PRIO_PROCESS,0);
$Prio += 1;
setpriority (&PRIO_PROCESS, 0, $Prio);
print "Neue Prioritaet des aktuellen Prozesses: $Prio\n";
 
print "</body></html>\n";
Das Beispiel liest mit getpriority die Priorität des aktuellen Prozesses ein, erhöht sie anschließend um 1 und setzt dann mit setpriority den neuen Wert. Zur Kontrolle gibt das Script den aktuellen Wert der Priorität aus.
Beachten Sie: Diese Funktion führt zu einem schweren Fehler, wenn das System keine Prozess- bzw. Benutzerverwaltung im Sinne von Unix kennt.

[Bearbeiten] sleep - aktuellen Prozess anhalten

Hält die Ausführung des Scripts für eine bestimmte Anzahl Sekunden an und fährt dann fort.

Erwartet als Parameter:

  1. die Anzahl Sekunden, die angehalten werden soll. Wenn nichts übergeben wird, wird "für ewig" angehalten.
Beispiel
#!/usr/bin/perl -w
 
use strict;
 
sleep(10);
exec("/usr/bin/perl","aufwachen.pl");
Das Beispiel wartet nach Aufruf von sleep(10) 10 Sekunden und führt dann mit exec ein anderes Script aus.

[Bearbeiten] system - Fremdprogramm aufrufen und eigenen Prozess erhalten

Ruft ein anderes Programm auf und ermittelt dessen Rückgabewert. Wenn Sie daran interessiert sind, welche Ausgaben das andere Programm erzeugt, sollten Sie die Funktion open mit dem Zeichen | oder qx(...) bzw. `...` (Backticks) benutzen.

Erwartet als Parameter:

  1. eine Zeichenkette oder eine Liste. Werden mehrere Parameter, also eine Liste, übergeben, wird der erste Parameter als das auszuführende Programm bzw. Kommando interpretiert, und die übrigen Parameter als Übergabeparameter für das Programm bzw. Kommando.

Gibt den Rückgabewert des ausgeführten Programms oder Kommandos zurück.

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
(my $Datei_1, my $Datei_2) = split(/&/,$ENV{'QUERY_STRING'});
my $Pfaddatei_1 = "/usr/web/daten/alt/".$Datei_1;
my $Pfaddatei_2 = "/usr/web/daten/neu/".$Datei_2;
my $Vergleich = system("cmp $Pfaddatei_1 $Pfaddatei_2 >/dev/null");
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Test-Ausgabe</title></head><body>\n";
if($Vergleich == 0) {
  print "<tt>$Pfaddatei_1</tt><br>und<br><tt>$Pfaddatei_2</tt><br><strong>sind gleich!</strong>!\n";
}
else {
  print "<tt>$Pfaddatei_1</tt><br>und<br><tt>$Pfaddatei_2</tt><br><strong>sind verschieden!</strong>!\n";
}
print "</body></html>\n";
Das Beispielscript ermittelt den Inhalt der CGI-Umgebungsvariablen QUERY_STRING, erwartet in dem übergebenen Parameter ein kaufmännisches Und (&) und trennt den Teil davor und den dahinter in die Skalare $Datei_1 und $Datei_2. Die beiden Daten werden als Dateien interpretiert. Ein Beispielaufruf des Scripts könnte lauten:

/cgi-bin/script.pl?news.htm&news.htm

Das Script hängt die beiden gleichnamigen Dateien an unterschiedliche Pfadnamen auf dem Server und erzeugt damit zwei unterschiedliche Dateipfadangaben in den Skalaren $Pfaddatei_1 und $Pfaddatei_2. Mit system wird nun der Shell-Befehl cmp (unter Unix) gestartet, der zwei Dateien daraufhin überprüft, ob sie gleich sind. Dem Befehl werden die beiden Skalare mit den Pfadangaben übergeben. Eine Ausgabe soll der Befehl in diesem Fall nicht erzeugen. Deshalb wird seine Ausgabe nach /dev/null umgeleitet. Der Rückgabewert des system-Aufrufs und damit des cmp-Befehls wird jedoch gespeichert, nämlich im Skalar $Vergleich. Wenn der Wert 0 ist, sind die verglichenen Dateien gleich, andernfalls unterschiedlich. Diese Information wird zurückgegeben.

[Bearbeiten] times - Laufzeit des aktuellen Prozesses ermitteln

Ermittelt die Laufzeit eines Prozesses (und, wenn vorhanden, seiner Kindprozesse) von der Erzeugung bis zum Ausführen dieses times-Aufrufs. Ermittelt werden für jeden Prozess jeweils zwei Werte: "user time" und "system time". Während "user time" bezeichnet, wie lange der Prozess selber gelaufen ist, gibt "system time" die Zeit an, wie lange der Prozess das Betriebssystem beschäftigt hat. Die Summe beider Zeiten ist die gesamte verbrauchte CPU-Zeit.
Die gemessenen Zeiten basieren auf so genannten Uhrenticks. Die Anzahl der Uhrenticks pro Sekunde ist auf Unix-Systemen einstellbar (TICKSPERSEC in der Datei conf.h).

Erwartet keine Parameter.

Gibt eine Liste mit Laufzeiten in Sekunden (Fließkommazahlen mit Angaben zu Sekundenbruchteilen) zurück. Schema:
($user_time,$system_time[,$user_time_Kind,$system_time_Kind,...])

Beispiel
#!/usr/bin/perl -w
 
use strict;
use CGI::Carp qw(fatalsToBrowser);
 
my $x;
for(my $i = 0; $i < 1000; $i++) {
  for(my $k = 0; $k < 100; $k++) {
    $x = $i * $k / time();
  }
}
 
my ($Systemzeit, $Userzeit) = times();
my $CPU_Zeit = $Systemzeit + $Userzeit;
 
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
print "verbrauchte Systemzeit: <strong>$Systemzeit</strong> Sekunden<br>\n";
print "verbrauchte Userzeit: <strong>$Userzeit</strong> Sekunden<br>\n";
print "verbrauchte CPU-Zeit: <strong>$CPU_Zeit</strong> Sekunden\n";
print "</body></html>\n";
Das Beispiel enthält zwei verschachtelte for-Schleifen, in denen sehr viel zu rechnen ist (es werden insgesamt 100.000 Funktionsaufrufe von time und Bruchzahlrechnungen durchgeführt). Anschließend ermittelt das Beispiel die benötigten Zeiten. Vom Aufruf der Funktion times werden die ersten beiden Listenelemente, also die für den aktuellen Prozess, in den Skalaren $Systemzeit und $Userzeit festgehalten. Aus der Summe dieser beiden wird noch die CPU-Zeit ermittelt und in $CPU_Zeit gespeichert. Zur Kontrolle gibt das Script die ermittelten Zeiten aus.

[Bearbeiten] wait - auf das Ende eines Kindprozesses warten

Unix-spezifischer Befehl.

Erwartet keine Parameter.

Beispiel
#!/usr/bin/perl -w
 
#use strict;
use CGI::Carp qw(fatalsToBrowser);
 
$| = 1;
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
my $Kind_pid = fork();
 
if($Kind_pid) {
  print "<p>Hier ist der Elternprozess.</p>\n";
  wait();
  print "<p>Der Kindprozess ist zuende.</p>\n";
}
else {
  print "<p>Hier ist der Kindprozess.</p>\n";
  exit(0);
}
print "</body></html>\n";
Das Beispiel erzeugt mit fork einen Kindprozess. Mit if($Kind_pid) wird abgefragt, ob der Skalar $Kind_pid einen Wert ungleich 0 hat. Ist das der Fall, werden Anweisungen ausgeführt, die zum Elternprozess gehören. Im Beispiel wird eine Meldung ausgegeben, dass sich das Script im Elternprozess befindet. Im else-Zweig, in den das Script gelangt, wenn Kind_pid den Wert 0 hat, wird dagegen ausgegeben, dass der Kindprozess aktiv ist.
Normalerweise würde erst der if-Zweig abgearbeitet, dann der else-Zweig. Durch die Anweisung wait() im if-Zweig wartet jedoch der Elternprozess auf das Ende des Kindprozesses, bevor er fortfährt. So wird vorher der else-Zweig abgearbeitet, und anschließend die letzte Meldung im if-Zweig ausgegeben.

[Bearbeiten] waitpid - auf das Ende eines Kindprozesses mit bestimmter Prozessnummer (pid) warten

Unix-spezifischer Befehl. Ruft im Gegensatz zu wait direkt das Betriebssystem auf.

Erwartet als Parameter:

  1. Die Prozessnummer (PID) des gewünschten Kindprozesses.
  2. Schalter (Flags - siehe Tabelle weiter unten)

Gibt die Prozessnummer (PID) des beendeten Prozesses zurück, oder -1, wenn der gewünschte Kindprozess nicht oder nicht mehr existiert. Auf manchen Systemen ist auch der Rückgabewert 0 möglich - er bedeutet, dass der Kindprozess noch immer läuft (d.h. ein Timeout beim Warten überschritten wurde).

Beispiel
#!/usr/bin/perl -w
 
#use strict;
use CGI::Carp qw(fatalsToBrowser);
use POSIX;
 
$| = 1;
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title>\n";
print "</head><body>\n";
my $Kind_pid = fork();
 
if($Kind_pid) {
  print "<p>Hier ist der Elternprozess.</p>\n";
 
  use POSIX ":sys_wait_h";
  do {
    my $Kind_pid = waitpid(-1,&WNOHANG);
  } until $Kind_pid == -1;
 
  print "<p>Der Kindprozess ist zuende.</p>\n";
}
else {
  print "<p>Hier ist der Kindprozess.</p>\n";
  exit(0);
}
print "</body></html>\n";
Das Beispiel tut das gleiche wie jenes bei wait. In diesem Fall wird jedoch mit einer do-until-Schleife gewartet, bis der Kindprozess zuende ist. Das ist der Fall, wenn die Funktion waitpid den Rückgabewert -1 liefert, der Kindprozess also nicht mehr existiert.

Der Funktion waitpid wird im Beispiel das Flag &WNOHANG übergeben. Die Konstanten dazu werden im Standardmodul POSIX definiert. Daher ist es erforderlich, dieses Modul so wie im Beispiel mit use POSIX ":sys_wait_h" einzubinden.
Die folgende Tabelle listet die Flags auf, die Sie an der Stelle übergeben können.

Flag: Bedeutung:
&WEXITSTATUS Enthält den Rückgabewert des Kindprozesses (genauer: die untersten 8 Bit, also einen Wert bis maximal 255).
&WIFEXITED Hat den Wert true oder 1, wenn der Kindprozess normal beendet wurde.
&WIFSIGNALED Hat den Wert true oder 1, wenn der Kindprozess durch ein unbeantwortetes Signal beendet wurde.
&WIFSTOPPED Hat den Wert true oder 1, wenn der Kindprozess angehalten wurde.
&WNOHANG Der aufrufende Prozess wird nicht blockiert, falls der Kindprozess nicht sofort reagiert. In einem solchen Fall wird waitpid() sofort beendet und liefert 0 zurück.
&WSTOPSIG Die Nummer des Signals, das zum Anhalten des Kindprozesses führte (das Anhalten des Kindprozesses) kann mit &WIFSTOPPED ermittelt werden.
&WTERMSIG Die Nummer des Signals, das vom Kindprozess nicht beantwortet wurde und deshalb zu dessen Beenden führte (ob dies der Fall ist, kann mit &WIFSIGNALED ermittelt werden.
&WUNTRACED waitpid() kehrt mit dem Status eines bereits gestoppten Kindprozesses zurück, dessen exit-Rückgabewert aber noch nicht abgefragt wurde.
Meine Werkzeuge
Namensräume

Varianten
Aktionen
Übersicht
Schnell‑Index
Mitmachen
Werkzeuge
Spenden
SELFHTML