/ / Czy mamy autochomp w Perlu? - perl, string, chomp

Czy w Perlu mamy autochomp? - perl, string, chomp

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 № 1

Wię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 chomped 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` );