2010-05-12 16 views
17

Encuentro una gran cantidad de frases Perl en línea. A veces quiero convertir estas frases sencillas en un guión, porque de lo contrario, olvidaré la sintaxis de un solo liner.¿Cómo puedo convertir Perl one-liners en scripts completos?

Por ejemplo, estoy usando el siguiente comando (de nagios.com):

tail -f /var/log/nagios/nagios.log | perl -pe 's/(\d+)/localtime($1)/e' 

que había que reemplazarlo con algo como esto:

tail -f /var/log/nagios/nagios.log | ~/bin/nagiostime.pl 

Sin embargo, no puedo descubrir la mejor manera de lanzar rápidamente esto en un guión. ¿Alguien tiene una manera rápida de lanzar estas frases ingeniosas en un guión de Bash o Perl?

+0

Para el registro: Tenga en cuenta que tuve un error tipográfico en mi post inicial. Dije "localtime", cuando realmente quise decir "localtime ($ 1)". Por lo tanto, al leer cualquier respuesta a continuación, asegúrese de utilizar el tiempo local ($ 1). –

+0

En realidad, sería mejor implementar 'tail -f' dentro del script de perl en lugar de conectarlo a él. Considere el siguiente código: 'tail -f some_file | perl -e exit', que contrariamente a las expectativas, nunca volverá. – TrueY

Respuesta

37

Puede convertir cualquier Perl de una sola línea en un guión completo haciéndolo pasar por el backend B::Deparse compilador que genera Perl código fuente:

perl -MO=Deparse -pe 's/(\d+)/localtime($1)/e' 

salidas:

LINE: while (defined($_ = <ARGV>)) { 
    s/(\d+)/localtime($1);/e; 
} 
continue { 
    print $_; 
} 

La ventaja de este enfoque sobre la decodificación del comando de línea manualmente es que esta es exactamente la forma en que Perl interpreta su script, por lo que no hay conjeturas. B::Deparse es un módulo central, por lo que no hay nada que instalar.

+0

Wow tantas buenas y correctas respuestas aquí. Esta publicación gana, debido a la sugerencia de "B :: Deparse". El paso 1 es migrar una línea a una secuencia de comandos. El paso 2 es a menudo extender ese script, y este método 'B :: Deparse' se asegura de que comencemos con una buena sintaxis. –

+0

Gracias, muy buen truco! – neurino

3
#!/usr/bin/env perl 

while(<>) { 
    s/(\d+)/localtime($1)/e; 
    print; 
} 

El ciclo while y la impresión es lo que -p hace automáticamente por usted.

8

Tome un vistazo a perlrun:

-p

hace que Perl para asumir el siguiente bucle alrededor de su programa, que hace que sea iterar sobre los argumentos de nombre de archivo tanto como sed:

LINE: 
while (<>) { 
    ... # your program goes here 
} continue { 
    print or die "-p destination: $!\n"; 
} 

Si un archivo nombrado por un argumento no se puede abrir por algún motivo, Perl lo advierte y pasa al siguiente archivo. Tenga en cuenta que las líneas se imprimen automáticamente. Un error que ocurre durante la impresión se considera fatal. Para suprimir la impresión, use el modificador -n. A -p anula un -n interruptor.

Los bloques BEGIN y END se pueden usar para capturar el control antes o después del bucle implícito, al igual que en awk.

Así que, simplemente tome este trozo de código, inserte su código en la línea "# su programa va aquí", y viola, ¡su secuencia de comandos está lista!

Por lo tanto, sería:

#!/usr/bin/perl -w 
use strict; # or use 5.012 if you've got newer perls 

while (<>) { 
    s/(\d+)/localtime($1)/e 
} continue { 
    print or die "-p destination: $!\n"; 
} 
7

Eso es realmente fácil de almacenar en un guión!

#! /usr/bin/perl -p 
s/(\d+)/localtime($1)/e 

La opción -e introduce el código Perl para ser ejecutado, lo cual se podría pensar en como una secuencia de comandos en la línea de comandos, de modo dejarlo de lado y pegar el código en el cuerpo. Deje -p en la línea shebang (#!).

En general, es más seguro apegarse a un máximo de un "grupo" de opciones en la línea shebang. Si necesita más, siempre puede arrojar sus equivalentes dentro de un bloque BEGIN {}.

No se olvide chmod +x ~/bin/nagiostime.pl

usted podría conseguir un poco más lujoso e incrustar la parte tail también:

#! /usr/bin/perl -p 

BEGIN { 
    die "Usage: $0 [ nagios-log ]\n" if @ARGV > 1; 
    my $log = @ARGV ? shift : "/var/log/nagios/nagios.log"; 
    @ARGV = ("tail -f '$log' |"); 
} 

s/(\d+)/localtime($1)/e 

Esto funciona debido a que el código escrito para usted por -p utiliza "magia" de Perl (2 -argumento) open que procesa tuberías especialmente.

Sin argumentos, transforma nagios.log, pero también puede especificar un archivo de registro diferente, , p. Ej.,

$ ~/bin/nagiostime.pl /tmp/other-nagios.log
3

hay algunas buenas respuestas aquí si desea mantener el one-liner-script se dio la vuelta y, posiblemente, incluso ampliar sobre ella, pero la cosa más simple que podría posiblemente trabajo es simplemente:

#!/usr/bin/perl -p 
s/(\d+)/localtime($1)/e 

Perl reconocerá los parámetros en la línea hashbang del script, por lo que en lugar de escribir el bucle completo, puede continuar realizando el bucle implícito con -p.

Escribiendo el ciclo explícitamente y usando -w y "use strict;" son buenos si planeas usarlos como punto de partida para escribir un guión más largo.

4

Robert tiene la respuesta "real" anterior, pero no es muy práctico. El modificador -p hace un poco de magia, y otras opciones tienen aún más magia (por ejemplo, echa un vistazo a la lógica detrás de la bandera -i). En la práctica, simplemente crearía un alias/función bash para envolver el delineador, en lugar de convertirlo en un script.

Alternativamente, aquí está tu oneliner como un script: :)

#!/usr/bin/bash 
# takes any number of arguments: the filenames to pipe to the perl filter 

tail -f [email protected] | perl -pe 's/(\d+)/localtime($1)/e' 
Cuestiones relacionadas