Comment faire deux commands consumr l'input de stdin séquentiellement?

Le script perl suivant consume-10-lines-and-exit lit dix lignes de stdin et les imprime. Après cela, il sort.

 #!/usr/bin/env perl use ssortingct; use warnings FATAL => 'all'; for (my $i = 0; $i < 10; $i++) { my $line = <STDIN>; print $line; } 

J'essaie de combiner consume-10-lines-and-exit et cat de telle sorte que les dix premières lignes d'input et consommées et imprimées par la première command puis le rest soient consommées par cat .

Le code suivant quelques extraits tout imprimer 1 à 10 au lieu de 1 à 13 comme je m'attendais.

 printf '1 2 3 4 5 6 7 8 9 10 11 12 13' \ | tr ' ' '\n' | { perl consume-10-lines-and-exit; cat; } printf '1 2 3 4 5 6 7 8 9 10 11 12 13' \ | tr ' ' '\n' | ( perl consume-10-lines-and-exit; cat ) printf '1 2 3 4 5 6 7 8 9 10 11 12 13' \ | tr ' ' '\n' | sh -c 'perl consume-10-lines-and-exit; cat' 

Existe-t-il une construction pour les commands de séquençage afin qu'ils lisent l'input de stdin jusqu'à ce qu'ils quittent et ensuite la command suivante continuera là où le précédent s'est arrêté?

Votre problème est que perl utilise une input en memory tampon, donc lit plus loin que les lignes que vous voulez consumr. Essayez cette version byte-byte:

 perl -e ' use ssortingct; use warnings FATAL => "all"; for (my $i = 0; $i < 10; $i++) { my $line; while(sysread(*STDIN,my $char,1)==1){ $line .= $char; last if $char eq "\n"; } print $line; }' 

L'utilisation des commands de regroupement permet de faire ce travail, mais le coupable est l'input que vous mettez dans les commands de regroupement, ce qui n'est pas possible.

POSIX définit dans la section INPUT FILE que:

Lorsqu'un utilitaire standard lit un file d'input recherché et se termine sans erreur avant qu'il n'atteigne la fin du file, l'utilitaire doit s'assurer que le décalage du file dans la description du file ouvert est correctement positionné juste après le dernier octet traité par l'utilitaire. Pour les files qui ne peuvent pas être recherchés, l'état du file offset dans la description du file ouvert pour ce file n'est pas spécifié

perl n'est pas un utilitaire standard, mais il y a de grandes chances qu'il suive la spécification standard. Si vous rendez votre file recherché, cela fonctionnera:

 $ seq 13 > /tmp/test $ {perl -e 'for($i=0;$i<10;$i++){$line = <STDIN>;print $line}'; cat;} </tmp/test 1 2 3 4 5 6 7 8 9 10 11 12 13 

Si vous ne souhaitez pas utiliser de file, vous pouvez forcer perl utiliser la couche inférieure qui appelle les appels système read() , write() , lseek() pour IO:

 $ seq 13 | { PERLIO=:unix perl -e 'for($i=0;$i<10;$i++){$line = <STDIN>;print $line}' cat } 

La mise en memory tampon peut également être désactivée en jouant avec les couches PerlIO (voir aussi perlrun ). En outre, cette boucle de style C maladroite et verbeuse peut être plus facilement écrite sous ... for 1..10 ou for my $i (1..10) { ... } .

 $ perl -E 'say for 1..12' \ | ( PERLIO=:unix perl -e 'print "perl " . scalar <STDIN> for 1..10'; cat ) perl 1 perl 2 perl 3 perl 4 perl 5 perl 6 perl 7 perl 8 perl 9 perl 10 11 12 $