2010-10-03 17 views
7

¿Cómo puedo implementar grep de Unix en Perl? Intenté usar el built-in grep de Perl. Aquí está el código que no está funcionando:¿Cómo puedo implementar Unix grep en Perl?

$pattern = @ARGV[0]; 
$file= @ARGV[1]; 

open($fp,$file); 

@arr = <$fp>; 

@lines = grep $pattern, @arr; 

close($fp); 
print @lines; 

Y, por cierto, estoy tratando única funcionalidad básica grep no todas las funciones y en segundo lugar que no quiero hacer procesamiento de cadenas mí mismo. Quiero usar grep incorporado o alguna función de Perl.

Gracias de antemano :)

Respuesta

13

En Perl para referirse toda una matriz que usamos @. Pero para referir los elementos individuales, que son escalares, usamos $.

Por lo tanto, es necesario utilizar $ y no @ en estas líneas:

$pattern = @ARGV[0]; 
$file= @ARGV[1]; 

también

este

@lines = grep $pattern, @arr; 

debe ser

@lines = grep /$pattern/, @arr; 

la grep en Perl tiene la sintaxis general de:

grep EXPR,LIST 

Evalúa la EXPR para cada elemento de LIST y devuelve el valor de la lista que consiste en aquellos elementos para los que la expresión evaluada como verdadera.

El EXPR en su caso está buscando el patrón $pattern en orden @arr. Para buscar necesita usar el /PATTERN/ sin el /, la cadena $pattern se evaluará como verdadera o falsa.

+0

- Gracias lo tengo. – TCM

+2

@coddadict, lo hiciste muy bien arreglando los errores en el código, pero esta pregunta y el enfoque utilizado por el usuario lo convierte en un 'problema casi xy' así que esta es una de esas situaciones en que el adoctrinamiento probablemente no está fuera del tema. Hubiera recomendado no leer todo el archivo al mismo tiempo (quería simular grep orientado a la línea), lo habría recomendado usando el grep {} en lugar del grep() solo para crear un buen hábito, y los tres argumentos abiertos Y aún más mostrarle el enfoque en línea (o alternativamente línea por línea con el tiempo) hubiera sido una ventaja. –

4

La funcionalidad básica "grep" ya está implementada. (= ~)

$string =~ /pattern/; 
+0

@ user131527: - ¡Gracias! – TCM

13

Por supuesto, la respuesta de codaddict está bien, pero me gustaría añadir algunas observaciones:

Siempre debe comenzar sus guiones con estas dos líneas:

use strict; 
use warnings; 

utilizan tres argumentos abierta y prueba de errores:

open my $fh, '<', $file or die "unable to open '$file' for reading : $!"; 

y debido a que tiene que use strict declarar todas las variables Por lo que su guión será como:

#!/usr/bin/perl 

use strict; 
use warnings; 

my $pattern = $ARGV[0]; 
my $file = $ARGV[1]; 

open $fh, '<', $file or die "unable to open file '$file' for reading : $!"; 
my @arr = <$fh>; 
close $fh; # close as soon as possible 

my @lines = grep /$pattern/, @arr; 

print @lines; 

Si el archivo es grande, puede evitar la leyó en su totalidad en la memoria:

#!/usr/bin/perl 
use strict; 
use warnings; 

my $pattern = qr/$ARGV[0]/; 
my $file= $ARGV[1]; 
print "pattern=$pattern\n"; 

my @lines; 
open my $fh, '<', $file or die "unable to open file '$file' for reading : $!"; 
while(my $line=<$fh>) { 
    push @lines, $line if ($line =~ $pattern); 
} 
close($fh); 
print @lines; 
+2

Puede reemplazar el 'push @ lines, $ line' en el ciclo while simplemente con 'print $ line' y evitar el uso de cualquier arrays. Si su archivo es "grande", entonces alguien o algo inevitablemente un día desencadenará un grep que devuelve casi todas las líneas del archivo. (e igualmente grande :-) – Randall

11

Puede aproximarse a una versión primitiva de grep directamente en la línea de comandos. La opción -e le permite definir un script Perl en la línea de comando.La opción -n ajusta su secuencia de comandos más o menos así: while (<>){ SCRIPT }.

perl -ne 'print if /PATTERN/' FILE1 FILE2 ... 

Un poco mejor aproximación de grep sería el prefijo del nombre de archivo en la parte frontal de cada partido impresa. Tenga en cuenta que este ejemplo, como el anterior, no pasa por la molestia de abrir ningún archivo. En su lugar, utilizamos la construcción <> de Perl para iterar a través de todos los archivos, y la variable $ARGV proporciona el nombre del archivo actual.

use strict; 
use warnings; 

my $pattern = shift; 

while (my $line = <>){ 
    print $ARGV, ':', $line if $line =~ $pattern; 
} 
+1

La variable especial '$ .' contiene el número de línea actual. Entonces, si quiere imprimir eso, también puede hacer 'perl -ne 'print" $ ARGV, $.: $ _ "Si/PATTERN /' file1 file2'. – hfs

13

Como ya aceptado una respuesta, estoy escribiendo esta respuesta de referencia para los futuros lectores en busca de problemas similares, pero no exactamente el suyo:

Como la gente ha respondido ya, la forma de simular grep con Perl es usar el enfoque en línea. Para el uso de perl como 'mejor' grep (y buscar y cortar y ...) recomiendo el libro minimal perl y tiene suerte porque el capítulo para 'perl as a "better" grep' es uno de los capítulos de muestra.

Aquí tienes más ejemplos inspirados en el libro:

perl -wnle '/foo/ and print' null.txt # normal grep 
perl -wnle '/foo/ and print "$ARGV: $_"' null.txt # grep -H 
perl -wnle '/foo/ and print $ARGV and close ARGV' null_1.txt null_2.txt # grep -l 

En el último ejemplo ARGV es el gestor de archivo actual, y como con -l que están interesados ​​en la búsqueda de archivos con el partido que puede imprimir el archivo nombrar e ir al siguiente archivo después de la primera coincidencia en un archivo.

También puedes buscar por el párrafo no por línea:

$ perl -00 -wnl -e '/\bBRIBE\b/i and print;' SenQ.testimony 
I knew I'd be in trouble if 
I ACCEPTED THE BRIBE! 
So I did not. 

My minimum bribe is $100k, and she only offered me $50k, 
so to preserve my pricing power, I refused it. 

O encontrar sólo el primer partido:

$ perl -00 -wnl -e '/\bBRIBE\b/i and close ARGV;' SenQ.testimony 
I knew I would be in trouble if 
I ACCEPTED THE BRIBE! 
So I did not. 

Y, finalmente, si se le pregunta acerca de grep y Perl, creo que parecían que debería mencionar ACK. Implementa, en perl, la funcionalidad grep y la extiende. Esta es una herramienta maravillosa y, además, puede tenerla también como un paquete de CPAN. Siempre he usado como línea de comando, no sé si puedes acceder a sus métodos directamente desde tus programas perl, pero esto sería muy bueno.

Cuestiones relacionadas