Hej,
Jeg har en bunke programmer skrevet i forskellige sprog, som alle udmærker
sig ved at bede om username+password, og så spytte en fil ud udfra noget
input. Disse er kædet sammen i en Makefile. Det virker fremragende, bortset
fra at det er lidt træls at skulle taste samme password 10 gange... og
desuden ville jeg gerne lave en frontend til det med lidt syntax
highlighting og sår'n. Det er jo jul :)
OK --- så vidt jeg kan se er mit problem altså følgende: Jeg ar en process
(make) der skaber noget output, dels på stdout, dels på stderr, og som
læser noget data en gang imellem (password+username). Så hvis jeg bare kan
læse det der bliver skrevet til/læst fra processen skulle det jo være let
nok.
Jeg finder hurtigt open3(), som lige er hvad jeg skal bruge. Der står en
masse om at man skal passe på, men de nævner også select() som er en kær,
gammel ven. Det skulle være en smal sag at kæde de to ting sammen, tænker
jeg. Men nej, skidtet vil ikke fungere. Uanset hvilket program jeg starter
får jeg øjeblikkeligt tilbage fra select() at der er noget fra stdout og
stderr, men hver gang der læses fra disse får jeg: "Resource temporarily
unavailable". A-hva? Jeg har lige lavet select() på den resource :(
Nogen bud? Koden, som er en simpel prototype, er nedenfor, og output under
koden. Bemærk at hvis man selecter på STDIN istedet for OUT, ERR virker det
helt fint, se evt. nederst.
-- asyn --
#!/usr/bin/perl -w
use IO::Select;
use IPC:
en3;
#XXX: for the future
$running = 1;
#install signal handler
$SIG{'CHLD'} = sub {
print "Reaping...";
waitpid( $pid,0 );
print "done\n";
$running = 0;
return 1;
};
$SIG{'PIPE'} = sub {
print "Pipe broke!";
$running = 0;
return 1;
};
#Open a program. In this case a small perl script including below.
$pid = open3(\*IN, \*OUT, \*ERR, '/home/esben/hello');
#$pid = open3(\*IN, \*OUT, \*ERR, '/bin/cat'); # Doesn't work, either.
#Set IO to non-blocking. Makes it easier to get the error messages.
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
$flags = fcntl(OUT, F_GETFL, 0)
or die "Can't get flags for the socket: $!\n";
$flags = fcntl(OUT, F_SETFL, $flags | O_NONBLOCK)
or die "Can't set flags for the socket: $!\n";
$flags = fcntl(ERR, F_GETFL, 0)
or die "Can't get flags for the socket: $!\n";
$flags = fcntl(ERR, F_SETFL, $flags | O_NONBLOCK)
or die "Can't set flags for the socket: $!\n";
# Set up select according to man IO::Select
$selectout = IO::Select->new(\*OUT, \*ERR ); # This doesn't work but
#$selectout = IO::Select->new(\*STDIN ); # ... this works as expected
$selectin = IO::Select->new(\*IN);
$selecterr = IO::Select->new(\*IN, \*OUT, \*ERR);
#while ($running) {
for (1..10) { # 10 loops are more than enough to show the problems
print "\nSelecting...";
# Select to get ready filehandles. The assignment sucks,
# but at least it should work
@myarr = IO::Select->select($selectin, $selectout, $selecterr, 10000);
@writers = @{$myarr[0]};
@readers = @{$myarr[1]};
@errors = @{$myarr[2]};
for $fh (@writers) {
print "Writing dummy to $$fh\n";
print $fh "dummy\n";
print "done\n";
}
for $fh (@readers) {
$rc = sysread($fh, $chunk, 2048); #XXX->future: call in loop
if ($rc) {
print "Read chunk from $$fh: <$chunk>\n";
} else {
print "Error while reading ($$fh): $!\n";
}
}
for $fh (@errors) {
print "Error in $$fh\n";
}
}
-- hello --
#!/usr/bin/perl -w
print "Name: \n";
$line = readline(STDIN);
for (1..10) { print "Hello $line"; }
--Ouput from asyn --
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
Selecting...Error while reading (*main::ERR): Resource temporarily
unavailable
Error while reading (*main::OUT): Resource temporarily unavailable
--- Output from asyn if
$selectout = IO::Select->new(\*OUT, \*ERR ); # This doesn't work but
#$selectout = IO::Select->new(\*STDIN ); # ... this works as expected
are swapped --
En hest
Selecting...Read chunk from *main::STDIN: <En hest
>
^C
--
mvh. Esben Mose Hansen
homepage:
www.mosehansen.dk --xxx-- GPG fingerprint:
www.mosehansen.dk/about.html