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

perl stdin

12216 просмотра

2 ответа

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

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

Проблема в том, что, если я пытаюсь читать из 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";
Источник Размещён: 17.05.2019 03:02

Ответы (2)


19 плюса

Решение

Встроенный 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";
  }
}
Автор: jj33 Размещён: 18.08.2008 03:12

0 плюса

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

#!/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);
}
Автор: Gus Schlachter Размещён: 21.02.2019 09:35
Вопросы из категории :
32x32