8

これは、Unix フォルダーを監視するための 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;
}
  • すべての課題の後に行うのchompは見栄えがよくありません。「オートチョップ」を行う方法はありますか?

  • 私は Perl を初めて使用するので、このコードを最適な方法で記述していない可能性があります。コードを改善するための提案は大歓迎です。

4

5 に答える 5

14

その場合、シェルを使用しないでください。

#! /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;

結果は少し異なります。dateコマンドの出力にはタイムゾーンが含まれますが、$date上記の値には含まれません。これが問題になる場合は、Chasによる優れた提案に従ってください。以下のオーエンスを使用strftimeして、必要な形式を取得します。

あなたのサブ

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

何か問題が発生した場合、サイレントに失敗します。サイレント障害は厄介です。次の行に沿ったコードの方が良いでしょう

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: $!";
    }
  }
}

systemバックティックは出力をキャプチャするためのものであるため、バックティックではなく使用する方が意図を表現できます。フォームはシェルをバイパスし、system(LIST)引数の引用について心配する必要があります。

シェルなしでシェルパイプラインの効果を得るということは、echo ... | mail ...自分で配管作業を少し行う必要があることを意味しますが、利点は、system(LIST)シェルの見積もりについて心配する必要がないことです。上記のコードは多くの引数を使用していますopen

MODEがの場合の3つ以上の引数の場合'|-'、ファイル名は出力がパイプされるコマンドとして解釈され、MODEが'-|'の場合、ファイル名は出力をパイプするコマンドとして解釈されます。2つの引数(および1つの引数)の形式では、ダッシュ('-')をコマンドに置き換える必要があります。この例の詳細については、perlipcでのIPCの使用openを参照してください。

上記はプロセスをopenフォークし、その標準入力に接続されています。親プロセス(まだ実行中のコード)はwithの役割を実行します。呼び出すと、ハンドルのI / Oバッファーに加えて、開いた方法のために少し余分なものがフラッシュされます。mail$fhtouchandmailechoprint $fh $msgclose

ファイルハンドルがパイプからのものである場合、関連する他のシステムコールの1つが失敗した場合、またはそのプログラムがゼロ以外のステータスで終了した場合はfalseopenを返します。close唯一の問題がプログラムがゼロ以外で終了したことであった場合、$!0に設定されます。パイプを閉じると、パイプで実行されているプロセスが終了するのも待機します(後でパイプの出力を確認したい場合に備えて)、暗黙的にそのコマンドの終了ステータス値をとに入れ$?ます${^CHILD_ERROR_NATIVE}

于 2010-09-12T11:01:08.440 に答える
6

より一般的には、このIO::Allモジュールは autochomp に相当するものを実際に提供します。

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

またはより一般的に:

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

確かに、この特定のケースでdateは、DateTimeモジュールの1つを使用する方がおそらく良いという他の回答者に同意しますが、単にファイルを読み込んですべての行をchomp編集したい場合IO::Allは、chompおよびtieオプションを使用します適用すると非常に便利です。

chompまた、ハンドルの内容全体をスカラーに直接スラープする場合、このトリックは機能しないことに注意してください(これは実装方法です)。

于 2010-09-12T13:45:07.620 に答える
5

それを関数に入れてみてください:

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

そして、実行したいコマンドごとにそれを呼び出してから、chompします。

于 2010-09-12T10:28:06.970 に答える
4

日付ユーティリティの代わりに、CPAN の DateTime またはその他の日付モジュールを使用します。

例えば:

use DateTime;

my $dt = DateTime->now;
print $dt->strftime('%Y%m%d%H%M.%S');
于 2010-09-12T10:33:11.957 に答える
2

chomp次の構文を使用して、1 行でand を割り当てることができます。

chomp ( my $date = `date` );

より Perlishly を話すことについては、同じことを何度も繰り返していることに気付いた場合は、それをサブにロールバックします。

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` );
于 2010-09-12T10:33:38.627 に答える