2010-09-12 20 views
8

Esto es lo que mi código Perl se parece a monitoring a Unix folder:¿Tenemos un autochomp en Perl?

#!/usr/bin/perl 
use strict; 
use warnings; 
use File::Spec::Functions; 

my $date = `date`; chomp $date; 
my $datef = `date +%Y%m%d%H%M.%S`; chomp $datef; 
my $pwd  = `pwd`; chomp $pwd; 

my $cache = catfile($pwd, "cache"); 
my $monitor = catfile($pwd, "monme"); 
my $subject = '...'; 
my $msg  = "..."; 
my $sendto = '...'; 
my $owner = '...'; 

sub touchandmail { 
    `touch $cache -t "$datef"`; 
    `echo "$msg" | mail -s "$subject" $owner -c $sendto`; 
} 

while(1) { 

    $date = `date`; chomp $date; 
    $datef = `date +%Y%m%d%H%M.%S`; chomp $datef; 

    if (! -e "$cache") { 
     touchandmail(); 
    } elsif ("`find $monitor -newer $cache`" ne "") { 
     touchandmail(); 
    } 
    sleep 300; 
} 
  • para hacer un chomp después de cada asignación no se ve bien. ¿Hay alguna forma de hacer un "autochomp"?

  • Soy nuevo en Perl y es posible que no haya escrito este código de la mejor manera. Cualquier sugerencia para mejorar el código es bienvenida.

+1

También es útil recordar que 'chomp' puede tomar una lista:' chomp ($ foo, $ bar, $ fubb) '. – FMc

Respuesta

14

Don No uses el caparazón, entonces.

#! /usr/bin/perl 

use warnings; 
use strict; 

use Cwd; 
use POSIX qw/ strftime /; 

my $date = localtime; 
my $datef = strftime "%Y%m%d%H%M.%S", localtime; 
my $pwd  = getcwd; 

El resultado es ligeramente diferente: la salida del comando date contiene una zona horaria, pero el valor de $date anterior no. Si esto es un problema, siga la sugerencia excelente al Chas. Owens a continuación y use strftime para obtener el formato que desea.

Su sub

sub touchandmail { 
    `touch $cache -t "$datef"`; 
    `echo "$msg" | mail -s "$subject" $owner -c $sendto`; 
} 

fallará silenciosamente si algo va mal. Las fallas silenciosas son desagradables. Mejor código sería lo largo de las líneas de

sub touchandmail { 
    system("touch", "-t", $datef, $cache) == 0 
    or die "$0: touch exited " . ($? >> 8); 

    open my $fh, "|-", "mail", "-s", $subject, $owner, "-c", $sendto 
    or die "$0: could not start mail: $!"; 

    print $fh $msg 
    or warn "$0: print: $!"; 

    unless (close $fh) { 
    if ($! == 0) { 
     die "$0: mail exited " . ($? >> 8); 
    } 
    else { 
     die "$0: close: $!"; 
    } 
    } 
} 

Usando system en lugar de acentos abiertos es más expresivo de su intención, porque son invertidas para la captura de salida. El formulario system(LIST) omite el shell y tiene que preocuparse por citar argumentos.

Obtener el efecto de la tubería de la carcasa echo ... | mail ... sin la carcasa significa que tenemos que hacer un poco el trabajo de fontanería nosotros mismos, pero el beneficio -como con system(LIST)- no es tener que preocuparse por las cotizaciones de la carcasa. El código anterior utiliza muchos argumento open:

Durante tres o más argumentos si el modo es '|-', el nombre del archivo se interpreta como una orden para que la producción debe ser canalizado, y si el modo es '-|', se interpreta el nombre del archivo como un comando que nos canaliza la salida.En el formulario de dos argumentos (y un argumento), se debe reemplazar el guión ('-') con el comando. Ver Using open for IPC in perlipc para más ejemplos de esto.

El open anteriormente horquillas un proceso mail, y $fh está conectada a su entrada estándar. El proceso primario (el código sigue ejecutándose touchandmail) realiza el rol de echo con print $fh $msg. Llamando close los buffers de E/S además del mango un poco más por la forma en la abrimos:

Si el gestor de archivo vino de un hilo open, close devuelve false si una de las otras llamadas al sistema que participan falla o si su programa sale con un estado distinto de cero. Si el único problema fue que el programa salió distinto de cero, $! se establecerá en 0. Cerrar una tubería también espera que el proceso que se ejecuta en la tubería salga, en caso de que desee ver la salida de la tubería después, y coloca implícitamente el valor de estado de salida de ese comando en $? y ${^CHILD_ERROR_NATIVE}.

+0

gracias por las sugerencias de touchandmail. Estaba pensando en incorporar algún manejo de errores para ello. – Lazer

+0

¿Qué es '" | - "'? – Lazer

+0

@Lazer: '| -' abre un conducto y redirige todo lo escrito en el manejador de archivos al stdin del nuevo proceso. –

5

Trate de poner en una función:

sub autochomp { 
    my $command = shift; 
    my $retval = `$command`; 
    chomp $retval; 
    return $retval; 
} 

y luego llamar a que para cada comando que desea ejecutar y luego masticar.

4

Use DateTime u otros módulos de fecha en CPAN en lugar de la utilidad de fecha.

Por ejemplo:

use DateTime; 

my $dt = DateTime->now; 
print $dt->strftime('%Y%m%d%H%M.%S'); 
+1

Para la fecha 'POSIX' es potencialmente aún más fácil/más clara: 'use POSIX qw/strftime /; mi $ date = strftime "% Y% m% d% H% M.% S", horario local; ' – Telemachus

2

Es posible asignar y chomp en una sola línea utilizando la siguiente sintaxis:

chomp (my $date = `date`); 

En cuanto a hablar más Perlishly, si usted se encuentra repitiendo la misma una y otra vez, rodéelo a un submarino:

sub assign_and_chomp { 

    my @result; 
    foreach my $cmd (@_) { 
     chomp (my $chomped = $cmd); 
     push @result, $chomped; 
    } 
    return @result; 
} 

my ($date , $datef , $pwd) 

    = assign_and_chomp (`date` , `date +%Y%m%d%H%M.%S` , `pwd`); 
+0

[' chomp'] (http://perldoc.perl.org/functions/chomp.html) "devuelve el número total de caracteres eliminados de todos sus argumentos, "no los resultados obtenidos. –

+0

@gbacon: Es por eso que estoy 'matando los escalares uno por uno – Zaid

+1

Pero su bucle empuja los valores devueltos de 'chomp' sobre' @ result'. –

6

De manera más general, el módulo IO::All proporciona realmente el equivalente de un autochomp:

use IO::All; 
# for getting command output: 
my @date = io("date|")->chomp->slurp; 
#$date[0] contains the chomped first line of the output 

o más en general:

my $fh = io("file")->chomp->tie; 
while (<$fh>) { 
# no need to chomp here ! $_ is pre-chomped 
} 

Por supuesto, para este caso particular de date estoy de acuerdo con los otros contestadores que probablemente es mejor usar uno de los módulos DateTime, pero si simplemente está leyendo en un archivo y quiere que todas sus líneas sean chomp ed, luego IO::All con las opciones chomp y tie aplicadas es muy conveniente.

Tenga en cuenta también que el truco chomp no funciona al sorber todo el contenido del mango en un escalar directamente (así es como se implementa).

Cuestiones relacionadas