Perl выполнить команду в указанное время

#perl #perl-module

#perl #perl-модуль

Вопрос:

Мне нужно написать сценарий perl, который выполняет команду в указанное время.

  1. используйте net::ssh::ожидайте входа в маршрутизатор
  2. считывает время с часов маршрутизатора (команда «показать часы» отображает время.)
  3. В 17:30:00 выполнить команду.

Я пытался написать для нее скрипт, но он не работает. Какие-либо предложения, пожалуйста?

 use strict;
use warnings;
use autodie;
use feature qw/say/;
use Net::SSH::Expect;

my $Time;
my $ssh = Net::SSH::Expect->new(
    host     => "ip",
    password => 'pwd',
    user     => 'user name',
    raw_pty  => 1,
);

my $login_output = $ssh->login();

while(1) {
    $Time = localtime();
    if( $Time == 17:30:00 ) {
        my $cmd = $ssh->exec("cmd");
        print($cmd);
    } else {
        print" Failed to execute the cmd n";
    }
}
 

Комментарии:

1. Я совершенно уверен, что это не работает, оно даже не компилируется. Я думаю, вам нужно попробовать немного больше…

2. Из любопытства, почему не cron для * nix или планировщика задач для Windows?

3. @ Chris Hamel: этот perl-скрипт будет интегрирован с другим perl-скриптом. Поэтому я не хочу устанавливать CRON.

Ответ №1:

Здесь несколько вещей:

Во-первых, используйте Time::Piece . Теперь это включено в Perl.

 use Time::Piece;
for (;;) {                   # I prefer using "for" for infinite loops
    my $time = localtime;    # localtime creates a Time::Piece object

    # I could also simply look at $time
    if ( $time->hms eq "17:30:00" ) {
        my $cmd $ssh->exec("cmd");
        print "$cmdn";
    }
    else {
        print "Didn't execute commandn";
    }
}
 

Во-вторых, вы не должны использовать подобный цикл, потому что вы собираетесь связывать процесс, просто повторяя цикл снова и снова. Вы можете попробовать перейти в режим ожидания до нужного времени:

 use strict;
use warnings;
use feature qw(say);
use Time::Piece;

my $time_zone = "-0500";    # Or whatever your offset from GMT
my $current_time = local time;
my $run_time = Time::Piece(
    $current_time->mdy . " 17:30:00 $time_zone",   # Time you want to run including M/D/Y
     "%m-%d-%Y %H:%M:%S %z");                      # Format of timestamp
sleep $run_time - $current_time;
$ssh->("cmd");
...
 

Что я здесь сделал, так это вычислил разницу между временем, которое вы хотите выполнить свою команду, и временем, которое вы хотите выполнить команду. Проблема возникает только в том случае, если я запускаю этот скрипт после 5:30 вечера по местному времени. В этом случае мне, возможно, придется проверить на следующий день.

Или, что еще лучше, если вы работаете в Unix, найдите crontab и используйте его. Crontab позволит вам точно указать, когда должна выполняться конкретная команда, и вам не нужно беспокоиться о ее вычислении в вашей программе. Просто создайте запись в таблице crontab:

 30 17 * * *  my_script.pl
 

30 И 17 скажите, что вы хотите запускать свой скрипт каждый день в 5:30 вечера. Другие звездочки обозначают день месяца, месяц и день недели. Например, вы хотите запускать свою программу только в будние дни:

 30 17 * * 1-5  my_script.pl  # Sunday is 0, Mon is 1...
 

В Windows есть аналогичный метод, называемый панелью управления расписанием, где вы можете настроить задания, которые выполняются в определенное время. Возможно, вам придется использовать perl my_scipt.pl , поэтому Windows знает, как использовать интерпретатор Perl для выполнения вашей программы.

Я настоятельно рекомендую использовать маршрут crontab. Это эффективно, гарантированно работает, позволяет вам сосредоточиться на вашей программе и не обманывать, когда выполнять вашу программу. Кроме того, он гибкий, все об этом знают, и никто не убьет вашу задачу, пока она сидит там и ждет 5:30 вечера.

Ответ №2:

localtime преобразует временную метку Unix (секунды с момента epoch, которая сейчас составляет около 1,4 миллиарда) в список значений. time Функция удобно предоставляет эту временную метку. От perldoc -f localtime :

 Converts a time as returned by the time function to a 9-element
        list with the time analyzed for the local time zone. Typically
        used as follows:

            #  0    1    2     3     4    5     6     7     8
            ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                                                        localtime(time);
 

Для вашего сравнения времени вы могли бы сделать:

 $Time = join ':', (localtime(time))[2, 1, 0];
if ($Time eq '17:30:00') {
    ...
}
 

Поскольку Perl позволяет [...] оператору postcircumfix индексировать списки точно так же, как это делается с массивами, мы можем использовать его для удаления фрагмента (localtime(time)) список, содержащий часы, минуты и секунды, соедините их двоеточиями и присвоите результирующей строке значение $Time.

Обратите внимание, что, поскольку $Time теперь содержит строку, вы должны сравнить ее с '17:30:00' , а не с простым словом 17:30:00 , которое не является допустимой числовой формой и должно привести к ошибке компиляции. И поскольку мы сравниваем строки вместо чисел, мы используем eq оператор. == вызывает числовой контекст для своих операндов, и поскольку 17:30:00 не является допустимым числом, Perl обработает его как 0 и предупредит вас с помощью

 Argument "foo" isn't numeric in numeric eq (==) at ....