Perl named regexp

Fórumok

Az lenne a feladat, hogy a /proc/drbd file-ból kiolvassam, hogy egy disk szinkrnizációja hol tart.
El kezdtem megoldani a dolgot, itt egy példa, hogy hogyan néz ki a forrás amit elemezni kell:
/proc/drbd :


GIT-hash: bb447522fc9a87d0069b7e14f0234911ebdab0f7 build by phil@fat-tyre, 2008-11-12 16:40:33

 1: cs:Connected st:Primary/Secondary ds:UpToDate/UpToDate C r---
    ns:721924 nr:3746432 dw:4472324 dr:5040 al:52 bm:46 lo:0 pe:0 ua:0 ap:0
	resync: used:0/61 hits:1217 misses:25 starving:0 dirty:0 changed:25
	act_log: used:0/257 hits:139646 misses:52 starving:0 dirty:0 changed:52
 2: cs:Connected st:Primary/Secondary ds:UpToDate/UpToDate C r---
    ns:0 nr:12 dw:12 dr:60 al:0 bm:0 lo:0 pe:0 ua:0 ap:0
	resync: used:0/61 hits:0 misses:0 starving:0 dirty:0 changed:0
	act_log: used:0/257 hits:0 misses:0 starving:0 dirty:0 changed:0
 3: cs:Connected st:Primary/Secondary ds:UpToDate/UpToDate C r---
    ns:117416 nr:119924 dw:122652 dr:130921 al:25 bm:63 lo:0 pe:0 ua:0 ap:0
	resync: used:0/61 hits:6891 misses:21 starving:0 dirty:0 changed:21
	act_log: used:0/257 hits:325 misses:25 starving:0 dirty:0 changed:25
 4: cs:Connected st:Primary/Secondary ds:UpToDate/UpToDate C r---
    ns:0 nr:0 dw:0 dr:284 al:0 bm:0 lo:0 pe:0 ua:0 ap:0
	resync: used:0/61 hits:0 misses:0 starving:0 dirty:0 changed:0
	act_log: used:0/257 hits:0 misses:0 starving:0 dirty:0 changed:0
 5: cs:SyncSource st:Primary/Secondary ds:UpToDate/Inconsistent C r---
    ns:735360 nr:0 dw:0 dr:735360 al:0 bm:44 lo:0 pe:0 ua:0 ap:0
	[>...................] sync'ed:  7.1% (9521/10239)M
	finish: 0:58:02 speed: 2,656 (2,240) K/sec
	resync: used:0/61 hits:45915 misses:45 starving:0 dirty:0 changed:45
	act_log: used:0/257 hits:0 misses:0 starving:0 dirty:0 changed:0

Ezt ezzel értelmezem:

#!/usr/bin/perl -w
# A script inditasa: reg-test.pl
use strict;
my $dev = shift;
open (PROC, "<fake_proc");
my @p = <PROC>;
our $line;
for ( $a=0; $a<scalar(@p); $a++ ){
chomp($p[$a]);
if ( $p[$a] =~ /^\s*$dev:/ ) {
$line = $p[$a+2];
chomp($line);
}
}
close (PROC);
$line =~ s/[\s\t]*\[.*sync\'ed:\ *([\0-9\.]+)\%.*$/$1/;

print "$line\n";

maga a regexp, tehát: s/[\s\t]*\[.*sync\'ed:\ *([\0-9\.]+)\%.*$/$1/;
és innen kellene segítség, mivel azt szeretném, hogy ha a sorban nincs benne a "sync'ed" a sorban akkor cserélje le completted -re a sort. Tudom, hogy írhatnék még egy sort de azt nem akarom. Olvasgattam a http://perldoc.perl.org/ -on a perlre részt, de nem igazán értem, hogy ezt hogyan lehet.
Tehát aki tud kérem segítsen.

Hozzászólások

szerintem igy lenne a legolvashatobb:

$line = ($line =~ s/sync\'ed:\ *([\0-9\.]+)/) ? $1 : 'Completed';

Már az eredetiben is gyanús, és itt is: mi a francnak van az s első paraméterében a 0 előtt backslash? (Ráadásul tudtommal szögletes zárójelen belül a . nem speciális, tehát azt se kéne takarni. Valamint nem látom, hogy miért nem használtok idézőjelet, és hogy hol van bezárva az s/// parancsban a "mire" sztring. Szóval szerintem ezeket a dolgokat kéne egy kicsit első körben finomítani :-) ).

Ui: Completed, egy t-vel :-)

"Már az eredetiben is gyanús, és itt is: mi a francnak van az s első paraméterében a 0 előtt backslash? (Ráadásul tudtommal szögletes zárójelen belül a . nem speciális, tehát azt se kéne takarni. "
ctrl+c, ctrl+v (ezt én sem értem :s )

"Valamint nem látom, hogy miért nem használtok idézőjelet,"
Hol kellene?

A pillanatnyi kód:


#!/usr/bin/perl -w
use strict;
my $dev = shift;
open (PROC, "<fake_proc");
my @p = <PROC>;
close (PROC);
our $line;
for ( $a=0; $a<scalar(@p); $a++ ){
    chomp($p[$a]);
    $line = $p[$a+2] if ( $p[$a] =~ /^\s*$dev:/ );
}
$line = ( $line =~ /^[\s\t]*\[.*sync\'ed:\ *([0-9.]+)\%.*$/ ? $1 : "completted" );
print "$line\n";

Ez most így eléggé változatos futásidőket produkál 4-9ms között ezen még gyúrok, de azért az eredeti kérdés még megválaszolatlan

Segítsetek!

----
概略情報

> Ez most így eléggé változatos futásidőket produkál 4-9ms között ezen még gyúrok

Nekem ez gyorsabbnak tűnik:


use strict;

my $dev = shift;

open PROC, '<', 'fake-proc.txt';
my @p; { local $/; @p = split( /[\r\n]+\s+(\d+): /, <PROC> ); }
close PROC;

print (($p[2*$dev] =~ /sync'ed:\s*([\d.]+)%/) ? $1: 'completed');

> az eredeti kérdés még megválaszolatlan

Nem jöttem rá, hogy mi az "eredeti kérdés". Talán tedd fel még egyszer.

Ja igen ... :)

Szóval az a kérdésem, hogy a fenti regexp -et hogyan írhatnám át úgy, hogy ha a kérdéses sorban, benne van a "sync'ed" akkor az utánna álló számot adja vissza, ha nincs benne akkor a completted szöveget.

Jelenleg ebben a formában van a script:


#!/usr/bin/perl -w
use strict;
my $dev = shift;
my $line;
open (PROC, "<fake_proc");
my @p = <PROC>;
close (PROC);
for ( $a=0; $a<scalar(@p); $a++ ){
    $line = ( $p[$a] =~ /^\s*$dev/ ? $p[$a+2] : $line );
}
$line = ( $line =~ /^[\s\t]*\[.*sync\'ed:\ *([0-9.]+)\%.*$/ ? $1 : "completted" );
print "$line\n";

Ez így 4ms futásidőt produkál (3.8 - 4.2 ms között)

----
概略情報

> ha a kérdéses sorban, benne van a "sync'ed" akkor az utánna álló számot adja vissza, ha nincs benne akkor a completted szöveget.

Nem értem. Az általad bemásolt kódban pont ez van:

( $line =~ /^[\s\t]*\[.*sync\'ed:\ *([0-9.]+)\%.*$/ ? $1 : "completted" )

> Ez így 4ms futásidőt produkál (3.8 - 4.2 ms között)

Az én kódom mennyit produkál?

És azt hiszem ez lesz a végleges megoldás:

#!/usr/bin/perl -w
use strict;
my $dev = shift;
my $line;
open (PROC, "</proc/drbd");
my @p = <PROC>;
close (PROC);
for ( $a=0; $a<scalar(@p); $a++ ){
$line = ( $p[$a] =~ /^\s*$dev/ ? $p[$a+2] : $line );
}
$line = ( $line =~ /ed: *([\d.]+)\%/ ? $1 : "completted" );
print "$line\n";

A futásidő kb 80%-át a file megnyitása és olvasása veszi el, úgyhogy nem lessz sokkal gyorsabb

----
概略情報

Megnéztem, mi ez a dbrd, de a for-ciklust nem értem...
Főleg, hogy ha a sebesség számít, akkor minek van egy rakás felesleges értékadás, az első találat után ki képne lépni a ciklusból.

Én egyetlen stringbe olvasnám be, aztán lehet regexelni...

/\n\s*$dev:.+\n.+\n.+?'.+?([\d]+)/

Az első sor eleje "GIT-hash", tehát biztos, hogy a device előtt van valami, így a device kikeresésére tökéletes a

/\n\s*$dev/

. Ezt és a következő sort nem kell figyelembe venni, erre jó a két

/.\n/

, főleg, hogy a

/./

nem illeszkedik a sorvégre, mert nem singleline keresés. Utána keresünk az aposztrófig, majd jön a százalékos érték (a százalékjelre teljesen felesleges keresni, a + harácsoló, amíg van számjegy vagy pont, addig "felzabálja".

Így a teljes kód ennyi:


#!/usr/bin/perl -w
use strict;
my $dev = shift;
local $/=undef;
open (PROC, "</proc/drbd");
my $p = <PROC>;
close (PROC);
print ($p=~/\n\s*$dev:.+\n.+\n.+?'.+?([\d]+)/?$1:'Completed').'\n';

Ez ugyanazt a hibát követi el, mint a Te kódod: ha a $dev-nek megfelelő blokk nem létezik, az eredménye "Completed".

(Remélem, nem írtam el, Windows alá nem raktam fel a Perlt.)

Na ez eddig a legkompaktabb megoldás.


#!/usr/bin/perl -w
use strict;
my $dev = shift;
local $/=undef;
open (PROC, "</proc/drbd");
my $p = <PROC>;
close (PROC);
print ($p=~/\n\s*$dev:.+\n.+\n.+?'.+?([\d.]+)/?$1:'Completed');
print "\n";

sajnos nem gyorsabb, de akkor is remek.
"Ez ugyanazt a hibát követi el, mint a Te kódod: ha a $dev-nek megfelelő blokk nem létezik, az eredménye "Completed"."
ez nem gond, mivel már az eszköz elkészülte után fogom ezt a függvényt hívogatni.

----
概略情報

Ami még számíthat sebességben:

1. A -w kapcsolónak jelen esetben semmi értelme, valójában a strict-nek sem.
2. Kihagyhatod az open/close párost (a fene tudja, lehet, hogy külön szálon lefut az open, amíg a perl fordít), ha a meghíváskor eleve a standard inputnak a /proc/drbd-t adod meg, valamint felesleges a shell-lel kitaláltatni, hogy ez perl kód:

perl holtartok.pl </proc/drbd

Így az egész ennyi:


my $dev = shift;
local $/=undef;
print (<>=~/\n\s*$dev:.+\n.+\n.+?'.+?([\d.]+)/?$1:'Completed').'\n';

Namost, ha idáig eljutottál, akkor, tekintve a kód hosszát - gyakorlatilag egyetlen regex - már simán átírhatod C-be is :), ezzel megúszod a perl fordítási idejét.

Csak egy kurta megjegyzés: ha fontos a tempó, és regexpes manipuláció kell, érdemes megfontolni az áthangszerelést awk-ra. Pár éve játszottam saját teljesítménytesztekkel, és sokat vert a perlre.