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

[gelöst] awk Skripting

Ok, dann der ganze Spaß eben nochmal in Perl:
Code:
#!/usr/bin/perl

use warnings;
use strict;

if($#ARGV < 0)
{
    print "Gimme a file-name!\n";
    exit(1);
}

my $s = $ARGV[0];

open(FH, "<$s");
my @a = <FH>;
close(FH);

my %e = ();
my $i;

foreach $i (@a)
{
    if($i =~ m/('.*' )/)
    {
        my $b = $1;
        my @c = split($b, $i);
        my $d = $c[1];
        chomp($d);

        if (exists $e{$b})
        {
            $e{$b} += $d;
        }
        else
        {
            $e{$b} = $d;
        }
    }
}

my @f = values(%e);
@f = sort { $b <=> $a } @f;

my %g = %e;
my $u;

for($i = 0; $i < 10; $i++)
{
    foreach $u (keys %g)
    {
        if($f[$i] == $g{$u})
        {
            print "$u $g{$u}\n";
            delete $g{$u};
            last;
        }
    }
}
Und sacht mir nich, dat et nich jeht !

Gruß
 
A

Anonymous

Gast
abgdf schrieb:
Und sacht mir nich, dat et nich jeht !
Na Prima, geht, und bringt auch noch die selben Ergebnisse wie awk. also treten dein Python mal in die Tonne ;)
Code:
priv0001:/tmp # time ./test8.pl test5 > /dev/null
real    0m0.039s
user    0m0.024s
sys     0m0.008s
priv0001:/tmp # time awk '{zeit[$1]+=$2} END{for (name in zeit) print zeit[name], name }' test5 | sort -nr | head > /dev/null
real    0m0.024s
user    0m0.004s
sys     0m0.012s
Aber : [Späßle gemacht]
Wir sind schon 2 Scripte weiter und du mußt auch noch etwas an der Performance deines Perlscriptes mache. Perl sollte ja 2 bis 20 mal schneller als awk sein. Also nun halte dich aber mal ein bisschen ran hier. [/Späßle gemacht]

robi
 
abgdf schrieb:
Ok, dann der ganze Spaß eben nochmal in Perl:
Naja mit perl geht das auch noch etwas kürzer :) (wobei man diese Version bestimmt auch wieder etwas kürzen könnte...)
Code:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

open(F, '<', 'l.txt') || die($!);
my %h;
while (<F>) {
  /'(.*)'\s+([\.\d]+)/;
  my $t = $h{$1} || {};
  $t->{'cnt'} += $2;
  $t->{'lines'}++;
  $h{$1} = $t;
}
%h = map { $_ => $h{$_}->{'cnt'} / $h{$_}->{'lines'} } grep { $h{$_}->{'lines'} >= 3 } keys %h;
print Dumper(\%h);
close(F);

}-Tux-{
 
Das Python-Problem hing, glaube ich, damit zusammen, daß ich immer noch Python 2.4 verwende (SuSE 10.0), während ihr wohl 2.6 habt. Sowas kann einem auch mit Perl passieren.
Vielleicht würde es gehen, wenn man im Skript statt "sre" nur "re" verwendet (in "import sre" und "b = sre.match("'.*'", i)").

Ich hab' da reguläre Ausdrücke verwendet, weil es eine Zeile
Code:
'bla/bla nochbla' 3.5
geben könnte. Sonst hätte ich direkt am Leerzeichen gesplittet.

Gruß
 
Hallo,

ein Perl-Skript weiter: Die Sache mit dem Durchschnitt:
Code:
#!/usr/bin/perl

use warnings;
use strict;

if($#ARGV < 0)
{
    print "Gimme a file-name!\n";
    exit(1);
}

my $fname = $ARGV[0];

open(FH, "<$fname");
my @lines = <FH>;
close(FH);

my %nr = ();
my %times = ();
my %result = ();
my $i;
my $u;

foreach $i (@lines)
{
    if($i =~ m/('.*' )/)
    {
        my $url = $1;
        my @temp = split($url, $i);
        my $time = $temp[1];
        chomp($time);

        if (exists $nr{$url})
        {
            $nr{$url}++;
        }
        else
        {
            $nr{$url} = 1;
        }

        if (exists $times{$url})
        {
            $times{$url} += $time;
        }
        else
        {
            $times{$url} = $time;
        }
    }
}

foreach $u (keys %times)
{
    $result{$u} = $times{$u} / $nr{$u};
    $result{$u} = sprintf("%.2f", $result{$u});
}

my @nrs = values(%result);
@nrs = sort { $b <=> $a } @nrs;

for($i = 0; $i < 10; $i++)
{
    foreach $u (keys %result)
    {
        if($nrs[$i] == $result{$u})
        {
            print "$u $result{$u}\n";
            delete $result{$u};
            last;
        }
    }
}
Was die Performance angeht, muß man berücksichtigen, daß Perl ein Skript immer erst ganz zu Bytecode durchkompiliert, bevor es es abarbeitet. Dadurch gibt es jeweils eine kurze Verzögerung beim Programmstart. Ob Perl nun immer so viel schneller als awk sein muß, kann ich auch nicht unbedingt sagen. Ist ja beides mit viel Sorgfalt in C implementiert ...
Kürzerer Code (Respekt }-Tux-{ !) ist auch nicht immer unbedingt schneller.
Ich denke, für ein paar tausend Einträge wird die Performance aber in jedem Fall reichen.

Hab' das Problem auch mal im Python-Forum geschildert:

http://www.python-forum.de/topic-16709.html

Da hat auch noch jemand (Y0Gi) eine schöne andere Lösung in Python geschrieben. Vielleicht läuft die dann ja auch bei euch.

Viele Grüße
 
A

Anonymous

Gast
Da hat auch noch jemand (Y0Gi) eine schöne andere Lösung in Python geschrieben. Vielleicht läuft die dann ja auch bei euch.
Ich glaube langsam musst du uns mal ein paar Tricks in Wiki schreiben wie man mit python Scripts umgeht. :???:

ich bekomme das Ding nicht zu laufen, habe schon alles probiert was mir eingefallen ist, irgendwie bekomm ich die Daten nicht durchs Script, bzw gar nicht erst rein. :eek:ps:
1. einfach so, kommt gleich Fehler in erster Zeile

2. Shebang #!/usr/bin/python es tut sich nichts scheint keine Eingabe zu bekommen

3. Shebang #!/usr/bin/env python es tut sich nichts scheint keine Eingabe zu bekommen

4.
Code:
./script.py datei.dat
/usr/bin/python script.py datei.dat
cat datei.dat | ./script.py
./script.py < datei.dat
überall das selbe, es tut sich nichts scheint keine Eingabe zu bekommen
Das kann doch nicht so kompliziert sein, oder doch :schockiert:

robi ratlos
 
A

Anonymous

Gast
}-Tux-{ schrieb:
Welches Script benutzt du denn? Das von abgdf? Falls ja, das funktioniert bei mir.
das lauft bei mir auf Fehler, ne, ich meinte das aus dem Python Forum. habs jetzt oben schon deutlicher gemacht. ;)

Hab jetzt Script noch mal neu kopiert, und reagiert schon etwas anders, Python-Scripte muss man wahrscheinlich behandeln wie schalenlose rohe Eier, aber funktionieren tuts trotzdem nicht.

versuch ich die Datei per Pipe oder < zu übergeben, kommt.
Code:
Traceback (most recent call last):
  File "./test8.py", line 10, in <module>
    url, access_time = line.strip().split(' ', 1)
ValueError: need more than 1 value to unpack
nehm ich die Datendatei als Argument zum Script, dann kann ich mit strace sehen, das er von der Tastatur lesen will und nicht aus der Datei. Ich glaube mal das ist nichts für meines Vaters Sohn ;)

robi ratlos
 
Hast du vielleicht eine Newline am Beginn oder am Ende des Files?
Das File braucht genau diese feste Struktur:
Code:
bla 123
blup 345

}-Tux-{
 
A

Anonymous

Gast
}-Tux-{ schrieb:
Hast du vielleicht eine Newline am Beginn oder am Ende des Files?
sicher hab ich da am Ende ein Newline, und das bekomme ich mit dem VI auch nicht weg, eventuell noch mit einem Hexadezimaleditor ;)
Code:
00000170  72 75 65 29 5b 3a 4c 49  4d 49 54 5d 3a 0a 20 20  |rue)[:LIMIT]:.  |
00000180  20 20 20 20 20 20 70 72  69 6e 74 20 27 25 38 2e  |      print '%8.|
00000190  34 66 20 20 25 73 27 20  25 20 72 65 73 75 6c 74  |4f  %s' % result|
000001a0  0a
Aber selbst wenn ich dieses mit \ entwerte oder mit Hilfe von dd beim kopieren wegschneide oder noch 1,2 oder 10 zusätzliche dazu mache reagiert das Programm immer gleich, nähmlich mit Fehler oder mit warten auf die Konsole.

Ich gebs auf, ich bin zu blöd für Python. ;)


robi
 
Hi,

in vi könntest Du die Leerzeile am Ende wohl wegkriegen, wenn Du mit "Shift+G" ganz ans Ende springst und da einmal "dd" eingibst. Dann mit ":w" speichern.
Wenn das wirklich das Problem ist, könnte mein Skript auch damit umgehen:
Code:
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

import os
import sys
import sre

s = sys.argv
if len(s) < 2:
    print "\nGimme a file-name!\n"
    sys.exit(1)

fh = file(s[1], "r")
a = fh.readlines()
fh.close()

e = {}

for i in a:

    if i == "" or i == "\n":
        continue

    # Needed, if filename contains " ":
    b = sre.match("'.*'", i)
    c = b.group()

    d = float(i.split(c + " ")[1].rstrip("\n"))

    if e.has_key(c):
        e[c] += d
    else:
        e[c] = d

f = e.values()
f.sort(reverse = True)

g = e.items()

for i in range(10):
    for u in g:
        if f[i] == u[1]:
            print u[0] + " " + str(u[1])
            g.remove(u)
            break
Y0Gi versucht in seinem Skript, die neuesten Python-Features einzusetzen. Kann sein, daß das nicht überall geht.
Aber eigentlich ist Python's Philosophie "Batteries included", das heißt, man soll möglichst wenig Module nachinstallieren müssen, alles sollte sofort funktionieren. Aber wenn man unbedingt die Standarddatentypen durch effizientere, extravagante ersetzen will, kann das zu Problemen führen.
Prinzipiell wollte Y0Gi aber von STDIN (auf pythonisch: sys.stdin) lesen, also wäre
Code:
cat datei.dat | skript.py
korrekt.

Wie auch immer, gibt's jetzt noch Probleme oder kommt man mit grep und den angebotenen Lösungen insgesamt zurecht ?

Gruß
 
Die awk-Version klappt tadellos, erstmal vielen Dank dafür robi und natürlich den restlichen Leuten.

Beste Gruesse
binbash
 
Da ihr bisher so freundlich wart, hätte ich noch eine Bitte an euch, die ihr sicherlich mit nem kurzen Code lösen könntet :)

Unter /opt/statistics/ sind die aktuellen Daten vom jeweiligen Tag hinterlegt, sprich

/opt/statistics/acces-time.2008-11-12.txt beinhaltet
90.4722 '/blog/uploadPhoto.action'
54.8582 '/profile/editActionPic.action'
....
....

/opt/statistics/access-time.2008.11.13.txt
41.5114 '/profile/editPortrait.action'
21.32 '/photos/createSeveral.action'
20.5394 '/useraccount/registerProfilePhoto.action'
..........
...

Aus all diesen Dateien hätte ich gerne die drei Einträge die am häufigsten vorkommen, daher meine Frage lässt sich das irgendwie realisieren ?
(Die Durchschnittliche Zeit wäre natürlich der Hammer ist allerdings nicht zwingend erforderlich)

Beste Gruesse
binbash
 
A

Anonymous

Gast
binbash schrieb:
Aus all diesen Dateien hätte ich gerne die drei Einträge die am häufigsten vorkommen, daher meine Frage lässt sich das irgendwie realisieren ?
(Die Durchschnittliche Zeit wäre natürlich der Hammer ist allerdings nicht zwingend erforderlich)
Code:
awk '{z[$2]+=$1;a[$2]++}END{for(n in z)print a[n],z[n]/a[n],n}' DATEI | sort -rn | head -3
Der nächste wird kostenpflichtig. ;) ;) ;) ;)

bei mehreren Dateien zusammen genommen sollte das hier wahrscheilnlich funktionieren. Leerzeilen o ähnliche Verunreinigungen sollten allerdings nicht dabei sein
Code:
cat DATEI* | awk '{z[$2]+=$1;a[$2]++}END{for(n in z)print a[n],z[n]/a[n],n}' | sort -rn | head -3
Wenn du öfter solche Auswertungen aus Listen, Tabellen oder ähnlichen Formaten zu machen hast, dann macht es schon Sinn wenn du dich mal selbst mit awk etwas beschäftigst. Der Wikiartikel http://wiki.linux-club.de/opensuse/Awk ist als Einstieg von mir so geschrieben worden, dass man (wie ich hoffe) mit etwas Konsolerfahrung in ein paar Stunden das Wichtigste beisammen hat, noch die angegebenen Links dazu und du bist in 3 Tagen awk-Guru.

Lehrbuch schrieb:
Awk ist einfach und seine Syntax ist übersichtlich (etwa 45 Seiten Spezifikation), Perl
ist aufgrund seines Umfanges und der ungewöhnlichen Syntax schwerer zu erlernen
(etwa 450 Seiten Spezifikation).

robi
 
Und wiedermal muss ich sagen Danke hast mir den AA gerettet :)

Ich habe den Wiki-Eintrag überflogen und muss sagen das ich mir vorgenommen habe, nähstes Wochenende awk zu widmen, mal schauen ob er dabei auf fruchtbaren Boden stößt.


Beste Gruesse
binbash
 
A

Anonymous

Gast
binbash schrieb:
Ich habe den Wiki-Eintrag überflogen und muss sagen das ich mir vorgenommen habe, nähstes Wochenende awk zu widmen, mal schauen ob er dabei auf fruchtbaren Boden stößt.
Du musst nur bis zum Beispiel 8 durchhalten ;) ;) ;)
Da hab ich für dich die letzte awk-Zeile mal entzaubert.

Ansonsten darfst du auch gerne mal was für meine Statistik tun, und das Thema auf gelöst setzen. ;)


robi
 
Das ganze verdient ja ein [gelöst] ² :)

Bis zum nähsten Problem :roll:


Beste Gruesse
binbash
 
Oben