2012-07-24 14 views
6

Sto provando a configurare pipeline arbitrarie da Perl, più o meno allo stesso modo di una shell.in esecuzione "minore" dalla pipeline perl

Questo ha l'effetto desiderato, è come "echo foo | sed s/oo/ar /":

#!/usr/bin/perl 
use strict; 

use IO::Handle; 

$| = 1; 

my ($first_prog, $second_prog) = ([qw(echo foo)], [qw(sed s/oo/ar/)]); 
#$second_prog = ["less"]; 

pipe(my $second_prog_input, my $first_prog_output) 
    or die "problem setting up pipe: $!\n"; 

if (fork) { 
    STDOUT->fdopen(fileno($first_prog_output), 'w') or die; 
    exec(@$first_prog) or die; 
} 
else { 
    STDIN->fdopen(fileno($second_prog_input), 'r') or die; 
    exec(@$second_prog) or 
     die "couldn't exec: $!: command was @$first_prog\n"; 
} 

Tuttavia, quando faccio il secondo argomento "meno", il mio terminale lampi, e io non vedere l'uscita nel cercapersone. Oltre al breve flash, non vi è alcun segno di una minore esecuzione.

Ora qualcosa che non capisco a tutti è che il seguente si comporta come "echo foo | less":

pipe(my $first_prog_output, STDIN) or die "problem setting up pipe: $!\n"; 

my ($first_prog, $second_prog) = ([qw(echo foo)], ["less"]); 

open($first_prog_output, "-|", @$first_prog) or 
    die "$!: command was @$first_prog\n"; 

exec(@$second_prog) or 
    die "couldn't exec: $!: command was @$first_prog\n"; 

Ma io non capisco affatto quello che chiamata a pipe() è facendo. Il primo argomento dovrebbe essere un "lettore", e il secondo uno "scrittore". In che modo STDIN è uno "scrittore"?

Sono molto confuso da tutto questo e penso che ci possa essere qualcosa di fondamentale nell'API Unix sottostante che mi manca o che ho dimenticato.

risposta

6

'un problema di temporizzazione interessante:

  • forcelle Shell, crea un gruppo di processi, imposta il primo piano gruppo terminale ad esso, ed esegue perl.
  • perl forche e dirigenti less.
  • perl exec echo.
  • echo uscite, shell crede che il lavoro sia fatto e si imposta di nuovo come gruppo terminale in primo piano.
  • less tenta di acquisire il terminale. Non è nel gruppo di processi in primo piano terminale. less non riesce.

La soluzione più semplice: il cambiamento fork a !fork (o equivalentemente, scambiare le vostre if e else blocchi). In questo modo, la fase finale della pipeline definisce la durata del lavoro. (Se si guarda attentamente, i processi di shell forks ed exec vengono eseguiti nello stesso ordine quando viene eseguita anche una pipeline.)