2012-09-10 11 views
6

Hay un archivo:Perl, deshabilitar la entrada de amortiguación

:~$ cat fff 
qwerty 
asdf 
qwerty 
zxcvb 

Hay un script:

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

El comando funciona como se esperaba:

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

Pero este comando no lo hará funcionar como se esperaba: el primer <STDIN> lee todos los datos, ni una sola línea. Cómo deshabilitar el almacenamiento en búfer para <STDIN>?

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

son '¿seguro fff gato. | perl-e 'system ("./ 1.pl")' 'imprime el contenido? para mi solo 'cat fff | perl 1.pl' hace. – tuxuday

Respuesta

6

Hay dos procesos de Perl aquí - la primera que asigna $_ = <STDIN> y llama system, y la segunda que hace print <STDIN>

Aunque sólo la primera línea de la corriente se lee en $_ por el primer proceso, Detrás de escena, Perl ha rellenado su búfer con datos y ha dejado la secuencia vacía

¿Cuál es el propósito de esto? La única forma en que se le ocurre hacer lo que pide es leer todos los del archivo en una matriz en el primer proceso, y luego quitar la primera línea y enviar el resto en una tubería al segundo script

Todo esto parece innecesario, y estoy seguro de que hay una mejor método si va a describir el problema subyacente

actualización

Desde dice ser consciente del problema de amortiguación, la manera de hacer esto es para usar sysread, que leerá de la tubería en un nivel inferior y evitará el almacenamiento en memoria intermedia

Algo como esto funcionará

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

Pero no me gusta recomendar como lo que está haciendo parece muy mal y me gustaría que explique su verdadero objetivo

+0

Puede leer una línea, 'tell', volver a abrir el archivo y' seek'. – choroba

+0

@choroba: Sí, pero no de una tubería – Borodin

+0

'$ cat fff | perl -ne'print a menos que $. == 1 '| ./1.pl' sería una solución poco elegante para eliminar la primera línea. – amon

0

recientemente he tenido para analizar varios archivos de registro que tenían alrededor de 6 gigabytes cada uno. El almacenamiento en búfer era un problema ya que Perl felizmente intentaría leer esos 6 gigabytes en la memoria cuando asignaría STDIN a una matriz ... Sin embargo, simplemente no tenía los recursos del sistema disponibles para hacer eso. Se me ocurrió la siguiente solución que simplemente lee el archivo línea por línea y, por lo tanto, evita el vórtice de memoria negra de memoria negra masiva que de otro modo tomaría todos mis recursos del sistema.

nota: Todo lo que hace este script es dividir ese archivo de 6 gigabytes en varios más pequeños (cuyo tamaño viene determinado por el número de líneas que debe contener cada archivo de salida). El bit interesante es el ciclo while y la asignación de una sola línea desde el archivo de registro a la variable. El ciclo iterará por todo el archivo leyendo una sola línea, haciendo algo con ella y luego repitiendo. Resultado, sin buffer masivo ... Mantuve todo el script intacto solo para mostrar un ejemplo de trabajo ...

#!/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 se invoca en la línea de comandos como:

(nombre del script) -i (archivo de entrada) -o (archivo de salida) -l (tamaño del archivo de salida (es decir, número de líneas)

Aunque no es exactamente lo que está buscando, espero que le dará algunas ideas :)

Cuestiones relacionadas