Как я могу протестировать STDIN без блокировки в Perl?

StackOverflow https://stackoverflow.com/questions/14118

  •  08-06-2019
  •  | 
  •  

Вопрос

Я пишу свое первое приложение на Perl - бот-мессенджер AOL, который общается с микроконтроллером Arduino, который, в свою очередь, управляет сервоприводом, который нажимает кнопку питания на сервере нашего системного администратора, который случайным образом зависает каждые 28 часов или около того.

Я выполнил всю сложную работу, я просто пытаюсь добавить последний фрагмент кода, чтобы прервать основной цикл и выйти из AIM, когда пользователь вводит "выйти".

Проблема в том, что если я пытаюсь прочитать из STDIN в основном цикле программы, это блокирует процесс до тех пор, пока не будут введены входные данные, по сути, делая бота неактивным.Я пробовал тестировать EOF перед чтением, но безрезультатно...EOF просто всегда возвращает false .

Ниже приведен пример кода, с которым я работаю:

while(1) {
    $oscar->do_one_loop();

# Poll to see if any arduino data is coming in over serial port
    my $char = $port->lookfor();

# If we get data from arduino, then print it
    if ($char) {
        print "" . $char ;
    }

    # reading STDIN blocks until input is received... AAARG!
    my $a = <STDIN>;
    print $a;
    if($a eq "exit" || $a eq "quit" || $a eq 'c' || $a eq 'q') {last;}
}

print "Signing off... ";

$oscar->signoff();
print "Done\n";
print "Closing serial port... ";
$port->close() || warn "close failed";
print "Done\n";
Это было полезно?

Решение

Встроенный Perl - это select(), который является проходом к select() системный вызов, но для здравомыслящих людей я рекомендую IO::Select.

Пример кода:

#!/usr/bin/perl

use IO::Select;

$s = IO::Select->new();
$s->add(\*STDIN);

while (++$i) {
  print "Hiya $i!\n";
  sleep(5);
  if ($s->can_read(.5)) {
    chomp($foo = <STDIN>);
    print "Got '$foo' from STDIN\n";
  }
}

Другие советы

Я обнаружил, что Ввод-вывод::Выбрать работает нормально до тех пор, пока стандартный вывод закрывается, например, когда завершается вышестоящий процесс в конвейере или ввод осуществляется из файла.Однако, если вывод продолжается (например, из "tail -f"), то любые частичные данные, буферизованные <STDIN> не будет отображаться.Вместо этого используйте небуферизованный системный просмотр:

#!/usr/bin/perl
use IO::Select;
$s = IO::Select->new(\*STDIN);

while (++$i) {
        if ($s->can_read(2)) {
                last unless defined($foo=get_unbuf_line());
                print "Got '$foo'\n";
        }
}

sub get_unbuf_line {
        my $line="";
        while (sysread(STDIN, my $nextbyte, 1)) {
                return $line if $nextbyte eq "\n";
                $line .= $nextbyte;
        }
        return(undef);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top