PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Dringend: Perl: 'Global symbol requires explicit package name at'



EliasP
06-09-2007, 12:18
Hallo zusammen,

habe ein dringendes Problem: Bin gerade dabei, das Nagios-Plugin 'check_mem.pl' auf HP-UX zum Laufen zu bringen, allerdings scheitere ich als Perl-Newb jetzt kläglich am Scope von Variablen.

Normalerweise wird über die Funktion 'sys_stats' die entsprechende Information ausgelesen. Ich habe das ganze jetzt entsprechend umgebaut, so dass es nicht mehr 'sys_stats' gibt, sondern 1x 'sys_stats_linux' und 1x 'sys_stats_hpux'.

Bisher wurde die Funktion 'sys_stats' so aufgerufen:


my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats();


Jetzt soll auf folgendem Weg je nach OS die jeweilige Funktion aufgerufen werden:



if ( `uname` == "HP-UX"){ my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_hpux(); }
if ( `uname` == "Linux"){ my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_linux(); }


Dadurch ändert sich jetzt aber der Scope der Variablen, da diese jetzt als lokale Variablen von if(){} gewertet werden.

Daraus resultierend bekomme ich beim Ausführen des Scripts jetzt Meldungen wie:


Global symbol "$swap_percent" requires explicit package name at ./check_mem.pl line 123.


Was muss ich machen, um den Scope für diese Variablen jetzt wieder global zu definieren? Vielleicht kann mir jemand auf die Schnelle helfen, sitze gerade beim Kunden und will das Problem möglichst schnell von der Bühne haben.

Vielen Dank im Voraus!

Gruß, Elias P.

P.S. Habe das Script angehängt.

Molaf
06-09-2007, 19:59
Einfach alle jemals zu benutzenden Variablen vorher mit

my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used, $..., $... , $...);
vormerken, dann ohne my in den ifs überschreiben.

Ansonsten das my jedesmal vor die Variablen, und nur die neuen Variablen, welche jeweils in den ifs eingeführt werden könnten vorher deklarieren.

reneeb
07-09-2007, 08:24
Zum Thema "use strict" (daher kommen die Fehlermeldungen) auch mal lesen: http://wiki.perl-community.de/bin/view/Wissensbasis/UseStrict . Da ist ganz gut erklärt warum man "use strict" verwenden sollte und warum da manchmal Fehler (wie Deiner) auftauchen.

Zu
if ( `uname` == "HP-UX"){ my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_hpux(); }
if ( `uname` == "Linux"){ my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_linux(); }

Warum machst Du zweimal `uname`? Da wird zweimal "uname" ausgeführt! Wenn Du "uname" verwenden willst, solltest Du das einmal ausführen und das Ergebnis weitervernden.

Dann gibt es in Perl noch die Spezialvariable $^O, die Angaben zum Betriebssystem enthält.

Außerdem solltest Du ein "elsif" verwenden, denn das Betriebssystem kann "nur" HP-UX oder Linux sein und nicht beides...

Ein Wortvergleich wird in Perl nicht mit "==" gemacht (das bleibt Zahlen vorbehalten), sondern mit "eq" (für "equals").

Also würde ich hier zwei Sachen vorschlagen:


my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used);
my $os = `uname`;

if ( $os eq "HP-UX"){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_hpux(); }
elsif ( $os eq "Linux"){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_linux(); }

Oder


my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used);

if ( $^O =~ /HP-UX/){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_hpux(); }
elsif ( $^O =~ /Linux/){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_linux(); }

Für erfahrene Perl-Entwickler würde ich zudem noch den "Dispatch-Hash" empfehlen:


my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used);
my $os = `uname`;

# Speichere in einem Hash die OS als Schlüssel und Referenzen auf Subroutinen als Wert
my %map = (
'HP-UX' => \&sys_stats_hpux,
'Linux' => \&sys_stats_linux,
);

# Wenn ein Eintrag für das OS in dem Hash existiert
if( exists $map{$os} ){
# führe die Subroutine, die im Hash gespeichert wurde aus (mittels $subreferenz->()
# die Subreferenz bekommt man ganz normal mit $hash{schluessel}
($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = $map{$os}->();
}


Edit: bei dem "Dispatch-Hash" ist mir ein Fehler unterlaufen. Die Klammern "()" bei den Sub-Referenzen müssen weg...

EliasP
07-09-2007, 13:11
Vielen Dank für eure ausführlichen Antworten! Werde das gleich mal testen und dann nochmal berichten.

Gruß, Elias P.

EliasP
07-09-2007, 16:09
Es hat jetzt soweit funktioniert, hänge allerdings noch an einem kleinen Problem:

Habe folgende Varianten zur Auswahl des Betriebssystems gebaut:


my $os=`uname`;
if ( $os eq "HP-UX" ){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_hpux(); }
elsif ( $os eq "Linux" ){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats_linux(); }
else { print "Unsupported OS\n"; exit $ERRORS{'UNKNOWN'}; }

bzw.


my $os=`uname`;
my %map = (
"HP-UX" => \&sys_stats_hpux(),
"Linux" => \&sys_stats_linux(),
);
if (exists $map{$os}){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = $map{$os}->(); }
else { print "Unsupported OS\n"; exit $ERRORS{'UNKNOWN'}; }


Führe ich es auf Linux aus, wird 'sys_stats_hpux' ausgeführt. Erkennbar an der folgenden Meldung:


sh: /usr/sbin/swapinfo: Datei oder Verzeichnis nicht gefunden
sh: /usr/sbin/swapinfo: Datei oder Verzeichnis nicht gefunden


Führe ich es auf HP-UX aus, wird anscheinend 'sys_stats_linux' ausgeführt. Meldung:


Illegal division by zero at ./check_mem.pl line 197.


Trage ich die jeweiligen 'sys_stats_...' hart ein, funktioniert es sowohl auf Linux als auch HP-UX, aber nicht, wenn ich die Entscheidung der if/else-Abfrage überlasse.

Irgendeine Ahnung was da schieflaufen könnte? So hochkompliziert ist das doch nicht.

Danke & Gruß, Elias P.

P.S. Aktuelle Version ist im Attachment

reneeb
07-09-2007, 16:34
Lass mal die Klammern bei den Sub-Referenzen weg, also


my $os=`uname`;
my %map = (
"HP-UX" => \&sys_stats_hpux,
"Linux" => \&sys_stats_linux,
);
if (exists $map{$os}){ ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = $map{$os}->(); }
else { print "Unsupported OS\n"; exit $ERRORS{'UNKNOWN'}; }