Hallo David, On Friday 27 October 2006 13:19, David Haller wrote:
Am Fre, 27 Okt 2006, Torsten Foertsch schrieb:
On Thursday 26 October 2006 16:40, David Haller wrote:
Mein Punkt war: diese (und andere) Option ist nicht standardisiert, und ist nicht bei jedem grep vorhanden. Teilweise selbst auf aktuellen Unix-Systemen nicht.
In dem Fall kann man nach der Option des gerade verfügbaren Grep zum Abschalten des gepufferten Schreibens fahnden. Falls es diese nicht gibt, kann man immer noch ein Pseudoterminal dafür benutzen. Kein Grep puffert den Output, wenn er auf ein Terminal schreibt. Das Ganze erfordert ein paar Zeilen Perl- oder C-Code. Das Perl-Modul IPC::Run kann dabei vielleicht helfen. Vielleicht gibt es sowas auch irgendwo in den Weiten des Internet schon fertig.
==== mklinebuffered.c ==== #include
#include #ifndef BUFSIZ # define BUFSIZ 8192 #endif int main(void) { char buf[BUFSIZ+1]; while( fgets( (char*)&buf, BUFSIZ, stdin) == buf ) { if( fputs( (char*)&buf, stdout) == EOF ) { perror(""); exit(errno); } if( fflush(stdout) != 0 ) { perror(""); exit(errno); } } return 0; } ====
$ make mklinebuffered $ ./mklinebufferd < ./FIFO | grep test
Das scheint zu funktionieren, solange das Programm, das nach ./FIFO schreibt nach seinen Ausgaben den Buffer "flushed".
Beispielsweise:
$ perl -e '$|=1;while(<>) { print $_;};' > ./FIFO
Zu beenden mit Strg+d.
Bei dem grep Problem geht es nicht darum, daß das Programm, das in den grep schreibt, puffert, sondern der grep selbst. Viele UNIX Programme puffern ihren Output solange sie nicht auf ein Terminal schreiben, so auch grep. Wie schon gesagt, kennen neuere greps die Option --line-buffered. Damit schreibt der grep jede Zeile extra. Für alte greps gibt es nur die Option, den Output über ein Pseudoterminal zu leiten. Nur so kann man ihm das Puffern abgewöhnen. In Perl geht das so: tailf file | perl -MPOSIX -MIO::Pty -e ' $|=1; my $pty=IO::Pty->new; $pty->autoflush(1); my $pid=fork; if($pid) { $pty->close_slave; while(defined($_=<$pty>)) {print} } else { POSIX::dup2($pty->slave->fileno, 1); close $pty->slave; close $pty; exec @ARGV; }' grep 1 | cat Jede Zeile, die nun in file erscheint und einen 1 enthält, wird sofort an cat weitergeleitet. Damit verhält sich diese Pipe genau wie tailf file | grep 1 Anders verhält sich tailf file | grep 1 | cat Hier puffert grep seinen Output, da er in eine Pipe und nicht auf ein Terminal schreibt. Erst wenn dieser Puffer voll ist, also nach einigen kByte, sieht cat Input. Ich hoffe, jetzt ist es etwas klarer, was ich meinte. Es gibt übrigens das Programm "unbuffer". Das macht genau das selbe; nur ist es kompiliert. tailf file | unbuffer -p grep 1 | cat Torsten