每2小时自动退出perl脚本

时间:2015-06-19 14:58:29

标签: linux perl command-line scheduled-tasks redhat

我有一个perl scipt,我需要它在Linux机器上每两个小时结束一次。我打算做一个单独的脚本并将其添加到cron.d来完成这个,但我想要一个更简单的方法。它必须做一个优雅的退出,因为在执行CTRL + C之后,它会写入一个日志文件并终止它不会写入该文件。

3 个答案:

答案 0 :(得分:3)

您可以在脚本的开头设置闹钟,并为其提供处理程序:

alarm 60 * 60 * 2;
local $SIG{ALRM} = sub {
    warn "Time over!\n";
    # Do the logging here...
    exit
};

问题是如何重新启动脚本。

答案 1 :(得分:1)

包装器使事情变得简单。

#!/usr/bin/perl

# usage:
#    restarter program [arg [...]]

use strict;
use warnings;

use IPC::Open3 qw( open3 );
use POSIX      qw( WNOHANG );


use constant RESTART_AFTER  => 2*60*60;
use constant KILL_INT_WAIT  => 30;
use constant KILL_TERM_WAIT => 30;
use constant WAIT_POLL      => 15;


sub start_it {
   open(local *NULL, '<', '/dev/null')
      or die($!);

   return open3('<&NULL', '>&STDOUT', '>&STDERR', @_);
}


sub wait_for_it {
   my ($pid, $max_wait) = @_;

   my $end_time = time + $max_wait;

   while (1) {
      if (waitpid($pid, WNOHANG) > 0) {
         return 1;
      }

      my $time = time;
      if ($end_time >= $time) {
         return 0;
      }

      sleep(1);
   }
}


sub end_it {
   my ($pid) = @_;
   kill(INT => $pid)
      or die($!);

   return if wait_for_it($pid, KILL_INT_WAIT);

   kill(TERM => $pid)
      or die($!);

   return if wait_for_it($pid, KILL_TERM_WAIT);

   kill(KILL => $pid)
      or die($!);

   waitpid($pid, 0);
}


sub run_it {
   my $end_time = time + RESTART_AFTER;

   my $pid = start_it(@_);

   while (1) {
      if (waitpid($pid, WNOHANG) > 0) {
         last;
      }

      my $time = time;
      if ($end_time >= $time) {
         end_it($pid);
         last;
      }

      my $sleep_time = $end_time - $time;
      $sleep_time = WAIT_POLL if $sleep_time > WAIT_POLL;  # Workaround for race condition.
      sleep($sleep_time);
   }

   my $status = $?;

   if    ($? & 0x7F) { warn("Child killed by signal ".($? & 0x7F)."\n"); }
   elsif ($? >> 8)   { warn("Child exited with error ".($? >> 8)."\n"); }
   else              { warn("Child exited with succcesfully.\n"); }
}


run_it(@ARGV) while 1;

您可能希望将发送给处理程序的信号转发给孩子。

答案 2 :(得分:-2)

您可以通过在$SIG{INT}中设置子程序来捕获Ctrl-C发送的信号:

$ perl -e '$SIG{INT} = sub { print "Caught signal, cleaning up\n"; exit 0 }; while(1) {}'

你在sub中进行清理,然后你去。