2012-09-10 1 views
6

Il y a un fichier:Perl, désactiver l'entrée de mémoire tampon

:~$ cat fff 
qwerty 
asdf 
qwerty 
zxcvb 

Il y a un script:

:~$ cat 1.pl 
#!/usr/bin/perl 
print <STDIN> 

La commande fonctionne comme prévu:

:~$ cat fff | perl -e 'system("./1.pl")' 
qwerty 
asdf 
qwerty 
zxcvb 

Mais cette commande ne sera pas fonctionne comme prévu: le premier <STDIN> lit toutes les données, pas une seule ligne. Comment désactiver la mise en mémoire tampon pour <STDIN>?

:~$ cat fff | perl -e '$_ = <STDIN>; system("./1.pl")' 
:~$ 
+0

Etes-vous sûr 'cat fff. | perl -e 'system ("./ 1.pl")' 'imprime le contenu? pour moi seulement 'cat fff | perl 1.pl' fait. – tuxuday

Répondre

6

Il y a deux processus Perl ici - la première qui attribue $_ = <STDIN> et appelle system, et le second qui fait print <STDIN>

Bien que seule la première ligne du flux est lu dans $_ par le premier processus, dans les coulisses Perl a rempli son tampon avec des données et laissé le flux vide

Quel est le but de cela? La seule façon qui vient à l'esprit pour faire ce que vous demandez est de lire tous du fichier dans un tableau dans le premier processus, puis retirez la première ligne et envoyer le reste dans une conduite au second script

Tout cela semble inutile, et je suis sûr qu'il ya une meilleure méthode si vous décrire le problème sous-jacent

Mise à jour

Puisque vous dites que vous êtes au courant du problème de mise en mémoire tampon, la façon de le faire est pour utiliser sysread, qui lira à partir du tuyau à un niveau inférieur et éviter le tampon

Quelque chose comme cela fonctionnera

cat fff | perl -e 'while (sysread(STDIN, $c, 1)) {$_ .= $c; last if $c eq "\n"} system("./1.pl")' 

Mais je n'aime pas recommander que ce que vous faites semble très mal et je souhaite vous expliquer votre objectif réel

+0

Vous pouvez lire une ligne, 'tell', rouvrir le fichier et' seek'. – choroba

+0

@choroba: Oui, mais pas d'un tuyau – Borodin

+0

'$ cat fff | perl -ne'print sauf $. == 1 '| ./1.pl' serait une solution inélégante pour enlever la première ligne. – amon

0

J'ai eu récemment analyser plusieurs fichiers journaux d'environ 6 gigaoctets chacun. La mise en mémoire tampon était un problème puisque Perl aurait heureusement essayé de lire ces 6 gigaoctets en mémoire quand j'attribuerais le STDIN à un tableau ... Cependant, je n'avais tout simplement pas les ressources système disponibles pour le faire. Je suis venu avec la solution de contournement suivante qui lit simplement le fichier ligne par ligne et, par conséquent, évite le vortex de mémoire tampon blackhole massive qui réquisitionnerait autrement toutes mes ressources système.

note: Tout ce script fait est divisé ce fichier de 6 gigaoctets en plusieurs plus petits (dont la taille est dictée par le nombre de lignes à contenir dans chaque fichier de sortie). Le bit intéressant est la boucle while et l'affectation d'une seule ligne du fichier journal à la variable. La boucle parcourt tout le fichier en lisant une seule ligne, en faisant quelque chose avec elle, puis en répétant. Résultat, pas de mise en mémoire tampon massive ... J'ai gardé tout le script intact juste pour montrer un exemple de travail ...

#!/usr/bin/perl -w 
BEGIN{$ENV{'POSIXLY_CORRECT'} = 1;} 
use v5.14; 
use Getopt::Long qw(:config no_ignore_case); 

my $input = ''; 
my $output = ''; 
my $lines = 0; 
GetOptions('i=s' => \$input, 'o=s' => \$output, 'l=i' => \$lines); 

open FI, '<', $input; 

my $count = 0; 
my $count_file = 1; 
while($count < $lines){ 
    my $line = <FI>; #assign a single line of input to a variable 
    last unless defined($line); 
    open FO, '>>', "$output\_$count_file\.log"; 
    print FO $line; 
    $count++; 
    if($count == $lines){ 
     $count=0; 
     $count_file++; 
    } 
} 
print " done\n"; 

script est appelé sur la ligne de commande comme:

(nom du script) -i (fichier d'entrée) -o (fichier de sortie) -l (taille de fichier de sortie (nombre de lignes)

Même si ce ne est pas exactement ce que vous cherchez, je l'espère, il vous donnera quelques idées :)

Questions connexes