Tak wygląda mój kod Perla monitorowanie folderu Unix :
#!/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;
}
Aby zrobić
chomp
po każdym zadaniu nie wygląda dobrze. Czy jest jakiś sposób na wykonanie „autochompowania”?Jestem nowym użytkownikiem Perla i może nie napisałem tego kodu w najlepszy sposób. Wszelkie sugestie dotyczące ulepszenia kodu są mile widziane.
Odpowiedzi:
14 dla odpowiedzi № 1Więc nie używaj powłoki.
#! /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;
Wynik jest nieco inny: wyjście date
polecenie zawiera strefę czasową, ale wartość $date
powyżej nie będzie. Jeśli jest to problem, postępuj zgodnie z doskonałą sugestią użytkownika Chas. Owens poniżej i użyj strftime
aby uzyskać pożądany format.
Twój sub
sub touchandmail {
`touch $cache -t "$datef"`;
`echo "$msg" | mail -s "$subject" $owner -c $sendto`;
}
zawiedzie bezgłośnie, jeśli coś pójdzie nie tak. Ciche awarie są nieprzyjemne. Lepiej byłoby kodować według linii
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: $!";
}
}
}
Za pomocą system
zamiast backticks jest bardziej wyrazisty zamiar, ponieważ backticks są do przechwytywania wyjścia. The system(LIST)
forma omija powłokę i musi martwić się o cytowanie argumentów.
Uzyskanie efektu rurociągu powłoki echo ... | mail ...
bez powłoki oznacza to, że musimy sami wykonać trochę pracy hydraulicznej, ale korzyści - jak w przypadku system(LIST)
- nie musi się martwić o cytowanie powłok. Powyższy kod używa wielu argumentów open
:
Dla trzech lub więcej argumentów, jeśli MODE jest
"|-"
, nazwa pliku jest interpretowana jako polecenie, do którego wyjście ma być potokowane, a jeśli jest to TRYB"-|"
, nazwa pliku jest interpretowana jako polecenie, które wysyła do nas dane wyjściowe. W postaci dwuargumentowej (i jednokrotnej) należy zastąpić myślnik ("-"
) poleceniem. Widzieć Za pomocąopen
dla IPC w perlipc więcej przykładów tego.
The open
powyżej widelce a mail
proces, i $fh
jest podłączony do standardowego wejścia. Proces nadrzędny (kod nadal działa touchandmail
) pełni rolę echo
z print $fh $msg
. Wywołanie close
opróżnia bufory we / wy uchwytu plus trochę więcej z powodu sposobu, w jaki je otwieraliśmy:
Jeśli uchwyt pliku pochodzi z potoku
open
,close
zwraca false, jeśli jeden z pozostałych wywołań systemowych zawiedzie lub jego program zakończy działanie z niezerowym statusem. Jeśli jedynym problemem było to, że program zakończył działanie niezerowo,$!
zostanie ustawiony na 0. Zamknięcie potoku również czeka na zakończenie procesu wykonanego na potoku - na wypadek, gdybyś chciał później spojrzeć na wyjście potoku - i niejawnie umieszcza wartość statusu wyjścia tego polecenia w$?
i${^CHILD_ERROR_NATIVE}
.
6 dla odpowiedzi nr 2
Bardziej ogólnie, IO::All
moduł rzeczywiście zapewnia odpowiednik autochomp:
use IO::All;
# for getting command output:
my @date = io("date|")->chomp->slurp;
#$date[0] contains the chomped first line of the output
lub bardziej ogólnie:
my $fh = io("file")->chomp->tie;
while (<$fh>) {
# no need to chomp here ! $_ is pre-chomped
}
Zgoda, w tym konkretnym przypadku date
Zgadzam się z innymi odpowiedziami, że prawdopodobnie lepiej będzie korzystać z jednego z modułów DateTime, ale jeśli po prostu czytasz plik i chcesz, aby wszystkie twoje linie chomp
ed IO::All
z chomp
i tie
zastosowane opcje są bardzo wygodne.
Zauważ także, że chomp
sztuczka nie działa, gdy cała zawartość uchwytu jest przeklejana bezpośrednio do skalara (tak właśnie jest zaimplementowana).
5 dla odpowiedzi nr 3
Spróbuj umieścić to w funkcji:
sub autochomp {
my $command = shift;
my $retval = `$command`;
chomp $retval;
return $retval;
}
Następnie wywołaj to dla każdego polecenia, które chcesz wykonać, a następnie chomp.
4 dla odpowiedzi № 4
Użyj DateTime lub innego modułu daty w CPAN zamiast narzędzia daty.
Na przykład:
use DateTime;
my $dt = DateTime->now;
print $dt->strftime("%Y%m%d%H%M.%S");
2 dla odpowiedzi № 5
Możliwe jest przypisanie i chomp
w pojedynczej linii przy użyciu następującej składni:
chomp ( my $date = `date` );
Jeśli chodzi o mówienie bardziej Perlishly, jeśli raz po raz powtarzasz to samo, wrzuć je do sub:
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` );