• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[ solved ]Leerzeilen entfernen in Perl

byron1778

Hacker
Hallo Forum!

Ich habe bei meinem Script folgendes Problem.
Ich lese mir mittels folgendem Script Daten aus Sybase aus

Code:
#!/bin/sh
isql -Usa -P -w500 -SJ7400DA1 -odb_groesse.txt -s";" << END-OF-INPUT
sp_helpdb
go
END-OF-INPUT

Als Ergebnis bekomme ich folgendes

Code:
;name                    ;db_size      ;owner                   ;dbid  ;created           ;status                                                                                                ;
;------------------------;-------------;------------------------;------;------------------;------------------------------------------------------------------------------------------------------;
;BACKUPTESTMXOE631       ;    3048.0 MB;sa                      ;    12;Aug 11, 2008      ;offline, mixed log and data                                                                           ;
;BACKUPTESTMXOE634       ;    3048.0 MB;sa                      ;    13;Aug 11, 2008      ;offline, mixed log and data                                                                           ;
;TESTDB                  ;    6000.0 MB;datamart                ;    14;Aug 20, 2008      ;select into/bulkcopy/pllsort                                                                          ;
;TESTMLC1                ;    1000.0 MB;LIMITS                  ;     5;Jun 09, 2008      ;mixed log and data                                                                                    ;
;TESTMLC1OE631           ;    1000.0 MB;sa                      ;    10;Jun 20, 2008      ;mixed log and data                                                                                    ;
;TESTMLC1OE634           ;    1000.0 MB;sa                      ;    11;Jun 20, 2008      ;mixed log and data                                                                                    ;
;TESTMLC2                ;    1000.0 MB;LIMITS                  ;     7;Jun 09, 2008      ;mixed log and data                                                                                    ;
;TESTMX1                 ;    2036.0 MB;sa                      ;     4;Jun 09, 2008      ;select into/bulkcopy/pllsort, mixed log and data                                                      ;
;TESTMX1_OLD             ;    2560.0 MB;sa                      ;    15;Sep 03, 2008      ;mixed log and data                                                                                    ;
;TESTMX2                 ;    2036.0 MB;sa                      ;     6;Jun 09, 2008      ;mixed log and data                                                                                    ;
;TESTMXOE631             ;    2048.0 MB;sa                      ;     8;Jun 20, 2008      ;mixed log and data                                                                                    ;
;TESTMXOE634             ;    2048.0 MB;sa                      ;     9;Jun 20, 2008      ;mixed log and data                                                                                    ;
;master                  ;      12.0 MB;sa                      ;     1;Jun 01, 2008      ;mixed log and data                                                                                    ;
;model                   ;       4.0 MB;sa                      ;     3;Jun 01, 2008      ;mixed log and data                                                                                    ;
;sybsystemdb             ;       5.0 MB;sa                      ; 31513;Jun 01, 2008      ;mixed log and data                                                                                    ;
;sybsystemprocs          ;     132.0 MB;sa                      ; 31514;Jun 01, 2008      ;trunc log on chkpt, mixed log and data                                                                ;
;tempdb                  ;    2052.0 MB;sa                      ;     2;Jul 23, 2008      ;select into/bulkcopy/pllsort, trunc log on chkpt, mixed log and data                                  ;

(1 row affected)
(return status = 0)

Leider sind am Anfang von jeder ca. 2ten Zeile Leerzeichen bzw. Leerzeilen.
Wenn ich nun mein Programm darueberlaufen lasse, damit ich nur die Datenbanken zurueckerhalte, dann bekomme ich immer wieder Warnings, weil ja der Leerstring so scheint es auch untersucht wird!

Code:
$string="name                    ";
$string2="------------------------";

$DIR_SYBASE="/scripts/sybase/db_groesse.txt";

                open(datei1, "<$DIR_SYBASE") || die $!;
                while(<datei1>) {
                                        @a=split(";",$_);
                                        $stringv=$a[1];
                                        if ( $string eq $stringv || $string2 eq $stringv )      {
                                                        next;
                                                                                                                }
                                        else    {
                                                        print "$stringv\n";
                                                }
                                }
                close(datei1);

So sehen die Warnings aus

Name "main::Eintraege" used only once: possible typo at ./testdb.pl line 41.
BACKUPTESTMXOE631
BACKUPTESTMXOE634
TESTDB
TESTMLC1
TESTMLC1OE631
TESTMLC1OE634
TESTMLC2
TESTMX1
TESTMX1_OLD
TESTMX2
TESTMXOE631
TESTMXOE634
master
model
sybsystemdb
sybsystemprocs
tempdb
Use of uninitialized value in string eq at ./testdb.pl line 32, <datei1> line 20.
Use of uninitialized value in string eq at ./testdb.pl line 32, <datei1> line 20.
Use of uninitialized value in concatenation (.) or string at ./testdb.pl line 36, <datei1> line 20.

Use of uninitialized value in string eq at ./testdb.pl line 32, <datei1> line 21.
Use of uninitialized value in string eq at ./testdb.pl line 32, <datei1> line 21.
Use of uninitialized value in concatenation (.) or string at ./testdb.pl line 36, <datei1> line 21.

Use of uninitialized value in string eq at ./testdb.pl line 32, <datei1> line 22.
Use of uninitialized value in string eq at ./testdb.pl line 32, <datei1> line 22.
Use of uninitialized value in concatenation (.) or string at ./testdb.pl line 36, <datei1> line 22.

Ich erhalte zwar die Datenbanken zurueck, aber genauso die Warnings; ich wuerde gerne aber dass das Programm richtig laeuft ohne Warnings.
Weiss jemand vll. wie ich das Programm umschreiben muesste, damit die Leerzeilen/Leerzeichen nicht mehr verglichen werden?

Danke vielmals im vorhinein!
 

Wizzzard

Member
Füge mal sowas in die while-Schleife ein:
Code:
chomp; # Entferne newline
if (m/^\s*$/) { next; } # wenn leere Zeile gehe an Anfang von while

Oder überprüfe nach dem Split die Länge von @a, wenn das kürzer ist als erwartet, gehe zur nächsten Zeile.

Die Länge von @a erhält man im skalaren Kontext.

Code:
my $number_of_columns_expected = 6;
if (@a < $number_of_columns_expected) { next; }
 
OP
B

byron1778

Hacker
Danke Dir vielmals!

Ich habe folgendes entdeckt:

Im vi behandelt er die Zeile nicht als leere Zeile sondern es ist eine ganze Zeile, somit war leider meine Angabe falsch.
Ich konnte es mit awk auf diese Art und Weise loesen

Code:
#!/bin/sh

isql -Usa -P -w5000 -SJ7400DA1 -odb_groesse.tmp -s";" << END-OF-INPUT
sp_helpdb
go
END-OF-INPUT

[b]cat /scripts/sybase/db_groesse.tmp | awk -F\; '{if (NF > 1) {print$2}}' > db_groesse.txt[/b]

Dein Code funktioniert auch groesstenteils, es spiesst sich nur, so scheint es, bei den letzten beiden Zeilen.

(1 row affected)
(return status = 0)

Aber das kann man sicher auch noch uebergehen!

Danke auf jeden Fall schon einmal!

mfG
 

regexer

Advanced Hacker
byron1778 schrieb:
(1 row affected)
(return status = 0)
Aber das kann man sicher auch noch uebergehen!
Wenn ich das richtig sehe beginnt bei dem Output jede Datenzeile mit einem Semikolon. Die zwei Kopfzeilen kann man ganz einfach weglassen, indem man erst ab der Dritten Zeile die Auswertung startet. Mein Vorschlag deshalb:
Code:
while(<datei1>) {
  next if ($. < 3);   # überspringe die ersten beiden Zeilen
  next unless (/^;/); # überspringe, wenn die Zeile nicht mit ";" beginnt
...
}
... das verwirft auch gleichzeitig die Leerzeilen
 
OP
B

byron1778

Hacker
Ich dachte mir ich stelle mal mein ganzes Programm jetzt hier hinein.
Wenn jemand, Verbesserungen, wie Performance, Code od so hat, bin gerne bereit jeden Ratschlag anzunehmen!

Code:
#!/usr/bin/perl -w
 
print <<HERE_DOKUMENT;
 
########################################################
#
# Author:       xxx
#
# Date:
#
# Changes:      26.08.2008      added databases Version 1
#               04.09.2008      everything in one Version 2
#               05.09.2008      coloured output of database size
#
# Description: Returns the size of databases
#
########################################################
 
HERE_DOKUMENT
 
########################################################
#
#               Variablen
#$DIR_SYBASE="/scripts/sybase/sybase_textdb/";
$datei="/scripts/sybase/sybase_textdb/datei.tmp";
#
#
########################################################
 
use Term::ANSIColor;
use Term::Cap;
 
$terminal = Term::Cap->Tgetent( {OSPEED => 9600} );
$clear_string = $terminal->Tputs('cl');
print "$clear_string";
 
$rc=system("isql -Usa -P -w5000 -SJ7400DA1 -o/scripts/sybase/sybase_textdb/db_groesse.tmp -s\";\" << END-OF-INPUT
sp_helpdb
go
END-OF-INPUT");
 
$rc=system('cat /scripts/sybase/sybase_textdb/db_groesse.tmp | awk -F\; \'{if (NF > 1) {print$2}}\' > /scripts/sybase/sybase_textdb/db_groesse.txt');
$rc=system('rm /scripts/sybase/sybase_textdb/db_groesse.tmp');
 

open(datei1, "</scripts/sybase/sybase_textdb/db_groesse.txt") || die $!;
open FILE, "> $datei" or die "Kann Datei $datei nicht oeffnen: $!\n";
while(<datei1>) {
                if (($_ =~ m/^name\s/) or ($_ =~ m/^---*\s/) or ($_ =~ m/BACKUPTESTMXOE631\s/) or ($_ =~ m/BACKUPTESTMXOE634\s/))  {
                next;
                                                                }
                else                    {
                print FILE "$_";
 
                                        }
                }
close FILE;
close (datei1);
 
open (FILE,"<$datei");
@datei= <FILE>;
close (FILE);
 
$laenge=$#datei;
 
for ( $i=0; $i<=$laenge; ++$i ) {
system("isql -Usa -P -w500 -SJ7400DA1 -o/scripts/sybase/sybase_textdb/db_groesse_$i.txt -s\";\" << END-OF-INPUT
sp_helpdb $datei[$i]
go
END-OF-INPUT");
                                }
 
unlink($datei); #datei.tmp faellt weg damit
 
$c=0;
$d=0;
 
for ( $i=0; $i<=$laenge; $i++ ) {
                open(datei1, "</scripts/sybase/sybase_textdb/db_groesse_$i.txt") || die $!;
                $c=0;
                while(<datei1>) {
                                if ($_ =~ /data and log\s/)     {
                                        @a=split(";",$_);
                                        $a[2] =~ /\s*(\d*\.?\d)\s/;
                                        $c+=$1;
                                        #print "c = $c\n";
                                        $a[5] =~ /\s*(\d*)/;
                                        $d+=$1;
                                        #print "d = $d\n";
                                                        }
                                }
                $d=int($d/1024);
                $e=int($c-$d);
                $e=int($e);
                if ( $e < 200 ) {
                        print "Frei sind: ";
                        print color 'bold red';
                        printf "%5d", $e;
                        print color 'reset';
                        print " MB in $datei[$i]";
                        close(datei1);
                                }
                else            {
                        print "Frei sind: ";
                        printf "%5d", $e;
                        print " MB in $datei[$i]";
                        close(datei1);
                                }
        }
print "\n";
 

Wizzzard

Member
Du rückst aber komisch ein!

Witzig finde ich in Perl-Programmen schon den Aufruf von AWK.

Hauptsache funktioniert.
 
OP
B

byron1778

Hacker
Ja, das mit dem Einrücken sieht komisch aus, gebe ich zu :)
Hat aber seinen Grund. Da ich nicht wie ein Adler mehr sehe, tue ich mir leichter damit, wenn ich alles mit Tabs trenne und die geschwungenen Klammern immer genau untereinander habe, somit muss ich nicht lange suchen, wenn ich einen Fehler produzieren sollte!

Das mit awk ergab sich dadurch, da ich nicht wusste, wie ich es mit Perl lösen könnte und mit awk ging es schneller. Aber ich mag auch keine "Bash - Aufrufe" in einem Programm wie Perl.

Über eine Lösung statt Perl würde ich mich natürlich freuen!
 

abgdf

Guru
Über eine Lösung statt Perl würde ich mich natürlich freuen!
Hatte ich für Dich mal bei diesem Thema

http://www.linux-club.de/viewtopic.php?f=28&t=93932

geschrieben. Und was war: Nicht mal ein Feedback, ob und wie es denn nun läuft !

Nee, dann macht's keinen Spaß ...

Gruß
 
OP
B

byron1778

Hacker
Sorry, war mit Sicherheit nicht beabsichtigt, dass ich damals nicht geantwortet habe.
War auf keinem Fall so gemeint.
Dein Programm hat wirklich sehr sehr gut funktioniert!
Tausend Dank dafür!
Ich muss sagen, ich war schwer beeindruckt, weil es beim Durchlesen so einfach und klar war, aber selber hätte ich es vermutlich nie hinbekommen, zumindest nicht in dieser Zeit!

Danke Dir nochmals und tut mir wirklich Leid, dass ich nicht geantwortet habe!

mfG
 
OP
B

byron1778

Hacker
Verständlich und akzeptiere es natürlich auch so!
Dass ich mich nicht rückgemeldet habe, war auch sicher nicht böse gemeint!

Entschuldigung nochmals!
 

abgdf

Guru
Die Entschuldigung nehme ich gern an.

Gut, dann werde ich mir mal das aktuelle Problem anschauen ...

Viele Grüße
 

abgdf

Guru
Hallo nochmal,

im Prinzip hast Du's ja schon. Die ursprüngliche Aufgabe wäre ich in etwa so angegangen:
Code:
#!/usr/bin/perl

use warnings;
use strict;

my $datei = "/scripts/sybase/sybase_textdb/datei.tmp";

open(FH, "<$datei") or die;
my @a = <FH>;
close(FH);

foreach (@a)
{
    chomp($_);

    my @b = split(";", $_);

    # $#b ist die Länge von @b - 1, also die Nummer des letzten Elements von @b:

    if ($#b > 0)
    {
        if ($b[1] eq "name                    " ||
            $b[1] eq "------------------------" ||
            $b[1] =~ m/BACKUPTESTMXOE631/ ||
            $b[1] =~ m/BACKUPTESTMXOE634/ )
        {
            next;
        }
        print "$b[1]\n";
    }
}
Ich lese Textdateien in der Regel erst in eine Listenvariable ein und arbeite dann mit dieser Variable anstatt dann immer noch mit einer "while(<>){}"-Konstruktion (letzteres ist IMHO mehr etwas für Perl-Einzeiler).
(Daß Dein Code insgesamt etwas übersichtlicher sein könnte, weißt Du, glaube ich, selbst :wink:.)

HTH (oder wolltest Du inzwischen noch etwas ganz anderes machen ?)
 
OP
B

byron1778

Hacker
Ja, dass mein Code etwas übersichtlicher sein könnte, weiss ich und muss dem auch zustimmen :)
Muss das Ganze endlich einmal in mehr Subs aufteilen.

Dein Code gefällt mir, wobei ich nicht so gerne mehrere 'Oder' oder 'Und' verschachtele.
Zudem sollen Regular Expressions angeblich nicht so schnell sein, deswegen versuche ich sie, wenn möglich wegzulassen oder zu umgehen.

Aber ein Aufruf eines akw macht das Ganze sicher nicht besser, das weiss ich!
 

Wizzzard

Member
byron1778 schrieb:
Zudem sollen Regular Expressions angeblich nicht so schnell sein, deswegen versuche ich sie, wenn möglich wegzulassen oder zu umgehen.

Vergiss es! Wenn Du keine Riesenprojekte schreibst, sondern Tools, die nur selten Laufen und wenig Kode enthalten, fällt das nicht ins Gewicht. Was bei den Regular-Expressions wohl eher zählen sollte, ist, dass man mit ihnen meist schneller ans Ziel kommt.
 
Oben