Zum Inhalt springen

Rechenungenauigkeiten in Perl & awk


Empfohlene Beiträge

Hallo zusammen,

ich habe die Aufgabe, ein Logfile (plaintext) von unserem Speichersystem auszuwerten. Das Logfile beinhaltet jeweils den Namen des aktuellen Ordners und die dazu gehörigen Dateien samt Größe und Speicherort (HDD / Tape Library). Um herauszufinden, welcher (Unter-)Ordner wie viel Speicherplatz verbraucht, habe ich mehrere "Programme" (in bash + awk, in Perl und in einem Excel-Sheet) geschrieben, die das Logfile auswerten und den Speicherverbrauch ähnlicher Ordner aufaddieren. Außerdem weiß ich, dass die Werte, die mir Excel liefert, die Richtigen sind. Leider bekomme ich bei meinen anderen Scripten zwar immer die ungefähr richtige Größenordnung heraus, die Ergebnisse unterscheiden sich je nach Speicherort aber um Größenordnungen von ca. 200 MB bzw. 70 GB. Ich würde nun gerne wissen, woher diese Ungenauigkeit kommen könnte. Überläufe in den Wertebereichen konnte ich bereits ausschließen.

Hatte vielleicht schon einmal jemand ein ähnliches Problem? Wo könnten die Ursachen liegen? Ich bin für jede Hilfe dankbar. Bei Bedarf könnte ich natürlich auch gerne mal den Code posten.

Vielen Dank und liebe Grüße, euer

Faultier

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi!

Tatsache ist, dass ich das Ganze erst in Bash / awk gemacht hab' und erst dann zu Perl umgeschwenkt bin, um 'ne befriedigendere Lösung zu erhalten. Hat nur leider nicht so geklappt, wie ich mir das gedacht hab'.

Außerdem zielte meine Frage auch eher auf allgemeine Gründe ab (wie z.B. ein Überlauf des Wertebereichs einer sein könnte) als auf konkrete Fehler im Quellcode. Nichtsdestotrotz hier der Perl-Code:


#!/usr/bin/perl


#######################

#      Includes       #

#######################


use English;

use HelpTools;    #eigenes Modul

use strict;

no  strict "refs";

use utf8;


#######################

#  Deklarationsteil   #

#######################


#Std.-Skalare

my $Source		= "out.txt";

my $RegExSource	= "prep.txt";

my $Dest		= "summ.txt";

my $Diag		= 0;				# Diagnoseausgaben (0 = AUS, 1 = AN)

my $Errors		= 0;

my $aktRegex	= "";

my $aktZeile	= "";

#Zähler

my $SizeHDD		= 0;

my $SizeBand	= 0;

my $countHDD	= 0;

my $countBand	= 0;

my $durchsuchte	= 0;

#Arrays

my @Regexe;

#Hashes

my %count;							#zählt für jeden Regex die Anzahl der gefundenen Zeilen => vielleicht finden wir dadurch raus, wo die Speicherdifferenzen herkommen


#######################

# Implementationsteil #

#######################


#Dateihandles oeffnen

sub openHandles(){

	#Quelldatei öffnen

	if (-e $Source){																							#Falls Datei existiert

		if (open (SOURCE_HANDLE, '<' , $Source)){print "Quelldatei \"$Source\" erfolgreich geoeffnet.\n" if ($Diag)}					#falls das Öffnen klappt

		else {die "Die Quelldatei \"$Source\" konnte nicht geoeffnet werden: $!.\n";}							#sonst Fehler melden

	}

	else {print "Die Quelldatei \"$Source\" existiert nicht: $!.\n";}											#sonst Fehler melden

	#Quelle für Regular Expressions öffnen

	if (-e $RegExSource){																						#Falls Datei existiert

		if (open (REGEX_HANDLE, '<' , $RegExSource)){print "Regex-Quelldatei \"$RegExSource\" erfolgreich geoeffnet.\n" if ($Diag)}		#falls das Öffnen klappt

		else {die "Die Regex-Quelldatei \"$RegExSource\" konnte nicht geoeffnet werden: $!.\n";}				#sonst Fehler melden

	}

	else {print "Die Regex-Quelldatei \"$RegExSource\" existiert nicht: $!.\n";}								#sonst Fehler melden

	#Zieldatei öffnen

	if (open (DEST_HANDLE, '>' , $Dest)){print "Zieldatei \"$Dest\" erfolgreich geoeffnet.\n" if ($Diag)}		#falls das Öffnen klappt

	else {die "Die Zieldatei \"$Dest\" konnte nicht geoeffnet werden: $!.\n";}									#sonst Fehler melden

	return 1;

}


#Dateihandles schliessen

sub closeHandles(){

	#Dateihandles schließen

	unless (close SOURCE_HANDLE) {die "Das Dateihandle zur Datei \"$Source\" konnte nicht geschlossen werden: $!.\n"; $Errors++;}

	unless (close REGEX_HANDLE) {die "Das Dateihandle zur Datei \"$RegExSource\" konnte nicht geschlossen werden: $!.\n"; $Errors++;}

	unless (close DEST_HANDLE) {die "Das Dateihandle zur Datei \"$Dest\" konnte nicht geschlossen werden: $!.\n"; $Errors++;}

	if ((!$Errors) && ($Diag)){print "Alle Dateihandles erfolgreich geschlossen. Programm wird beendet.\n";}

	return 1;

}


#Ergebnisse in die Ausgabedatei schreiben

sub Ausgabe(){

	print DEST_HANDLE "$_[0]\t\t$countBand\t$SizeBand\t$countHDD\t$SizeHDD\n";

	#print "$aktRegex\t$countHDD\t$SizeHDD\t$countBand\t$SizeBand\n";

	return 1;

}


#alle RegExes aus Datei in ein Array übertragen

sub prepareRegex(){

	#Regexe aus Datei lesen

	while (<REGEX_HANDLE>){

		chomp;

		push (@Regexe, $_);

	}

	#Diagnoseausgabe

	if ($Diag){

		foreach my $Regex (@Regexe){

			print DEST_HANDLE "REGEXE: " . $Regex . "\n";

		}

		print DEST_HANDLE "======================================================================================\n";

	}

	return 1;

}


&openHandles();

&prepareRegex();

print DEST_HANDLE "Ordnername\tAnzahlBand\tGroesseBand\tAnzahlPlatte\tGroessePlatte\n\n";

foreach my $Regex (@Regexe){

	if ($Regex ne ""){

		seek(SOURCE_HANDLE, 2, 0);		#seek(DATEIHANDLE, Zeilennummer (ab 1 indiziert), Offset);

		while (<SOURCE_HANDLE>){

			#chomp;

			#print "Zeile: " . $_ . "\n";

			$aktZeile = $_;

				#Beispielzeile:		san-work-goobi-backup.dir	14	4032	2	2.72933e+09

				#if ($aktZeile =~ m/$aktRegex/gi){

				if ($aktZeile =~ m/$Regex\t/gi){

					#$aktZeile =~ m/\t(\d+)/gi;										#Spalte 1

					$aktZeile =~ m/(\d+)\t(\d\.?\d+e\+\d{2}|\d+)\t(\d+)\t(\d\.?\d+e\+\d{2}|\d+)/gi;

					$countHDD += $1;

					$SizeHDD += $2;

					$countBand += $3;

					$SizeBand += $4;

					$count{$Regex} += 1;

				}

			$durchsuchte++;				# = Regexe * zu pruefende Zeilen

		}

		&Ausgabe($Regex);

		#Zaehlvariablen fuer naechsten Unterordner zuruecksetzen

		$SizeHDD = 0;

		$SizeBand = 0;

		$countHDD = 0;

		$countBand = 0;

	}

}


print DEST_HANDLE "Durchsuchte: $durchsuchte." if ($Diag);

while ( my ($k,$v) = each %count ) {

    print "$k => $v\n";

}

&closeHandles();

Der AWK-Code sieht so aus:

BEGIN {

	AnzB=0;

	AnzP=0;

	SizeB=0;

	SizeP=0;

	#OFMT="%.15g";		#Output Format

	OFMT="%i";			#Output Format

}


AnzB+=$4;

AnzP+=$2;


SizeB+=($5);		# kommt in Bytes aus der Datei

SizeP+=($3);		# kommt in Bloecken zu je 1 kB aus der Datei


END {

	print(Arg "	" AnzB "	" SizeB "	" AnzP "	" SizeP);

}

Die verwendeten Dateien. out.txt sieht auszugsweise so aus:
Name AnzahlHDD GroesseHDD AnzahlBand GroesseBand san-work-goobi-backup.dir 14 4032 2 2729330665 san-work-goobi-collect-2nd 6 24 0 0 san-work-goobi-collect-aix 1 1096 0 0 san-work-goobi-collect-hp11 1 1104 0 0 san-work-goobi-collect-linux86 1 748 0 0 ... hier folgen weitere
prep.txt sieht auszugsweise so aus:
backup.dir collect collect-2nd collect-aix collect-hp11 collect-linux86 collect-solaris ... hier folgen weitere
So, ich hoffe, ich hab' erst mal nix vergessen. Vielen Dank übrigens für deine schnelle Antwort! Bis bald, DasFaultier EDIT: Hab' natürlich doch noch was vergessen. Erstens das Aussehen der summ.txt, die da entstehen soll:
Ordnername AnzahlBand GroesseBand AnzahlPlatte GroessePlatte backup.dir 2 2729330665 14 4032 collect 0 0 10 4556 collect-2nd 0 0 6 24 collect-aix 0 0 1 1096 collect-hp11 0 0 1 1104 collect-linux86 0 0 1 748 collect-solaris 0 0 1 1180 collect-work05 0 0 1 440 ... hier folgen weitere
und zweitens das Bash-Script:

#!/bin/bash


#Verwendung:	"./summ.sh"

#WICHTIG:		Da die Datei "sehrKurzeVerzeichnisliste.txt" ausgewertet wird, müssen Sie durch Aufruf des Programms "kompletteVerzeichnisListe.sh" sicherstellen, dass diese auch existiert.


sed "s/^-//gi" sehrKurzeVerzeichnisliste.txt | sed "s/\s/_/gi" > prep.txt

echo "Ordnername	AnzahlBand	GroesseBand	AnzahlPlatte	GroessePlatte";

echo;

for ELEMENT in `more prep.txt`; do

	ELEMENT="$ELEMENT	";			# Tabulator anfuegen, um nur Wurzelverzeichnisse zu triggern (alle Unterverzeichnisse bleiben unangetastet)

	grep -e "${ELEMENT}" out.txt | gawk -v Arg="${ELEMENT}" -f ./summ.awk | grep -v "san-";

done

#rm prep.txt;	#Kommentierung entfernen, um temporäre Datei "prep.txt" nach Ausführung des Scriptes zu löschen

Als kurze Erklärung vielleicht noch: out.txt ist das Ergebnis des ersten Zwischenschrittes der Berechnungen. Die Ergebnisse in dieser Datei sind verifiziert und richtig. Hier wird der verwendete Speicherplatz pro Unterverzeichnis aufaddiert. In prep.txt liegen verkürzte Pfade aller ähnlich klingenden Unterverzeichnisse. summ.txt enthält dann die Summe des Speicherplatzes aller ähnlich klingenden Unterverzeichnisse.

Bearbeitet von DasFaultier
Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...