2015-09-28 2 views
2

Прошу прощения за этот действительно основной вопрос, но, похоже, я не нашел первопричину моей проблемы.Perl функция выбора навешивается бесконечно

детали окружающей среды: Perl 5.14.1 Подключение к MS SQL Server с помощью FreeTDS Tsql Linux x64

Вот мой код:

#!/usr/bin/perl -w 
use IO::Select; 
use strict; 

my $query = ""; 
my $s = IO::Select->new(); 
$s->add(\*STDIN); 
my @STD_IN =(); 
if ($s->can_read(.5)) { 
     @STD_IN = <STDIN>; 
     } 
$query .= "@STD_IN\[email protected]"; 

my $myTmpFile = `mktemp /tmp/$ENV{USER}QueryXXXX`; chomp($myTmpFile); 
`echo "use testDB\n$dbQuery\ngo\nquit" > $myTmpFile`; 

print(`/usr/bin/tsql -H myhost -p 9999 -U myuser -P mypass -o q < $myTmpFile`); 

Когда я запускаю этот сценарий, как этот

$>./myscript "select * from mytable" 

это нормально работает, но часто я вижу, что скрипт висит неопределенно.

Я сделал некоторые отладки, запустив ps -ef вот как это выглядит:

kedar 24659 24574 0 05:50 ttyp3 00:00:00 /usr/bin/perl -w /home/kedar/myscript select * from mytable 

Что может быть причиной для зависания здесь? Я пока не понимаю - это очень простой скрипт.

Я проверил PERL документацию для IO :: Выбор и это то, что он говорит -

can_read  

$s->can_read([timeout]) 
Returns array of handles that are ready for reading. timeout is the maximum amount of time to wait before returning an empty list. If timeout is not given, and any handles are registered, then the call blocks. 

Но у меня есть тайм-аут в моем сценарии.

Любая идея? Пожалуйста, помогите, поскольку я застрял в выпуске

PS: Некоторые переменные, имена файлов и другие вещи были изменены с оригинала из-за небольшого количества ограничений. Кроме того, этот скрипт написан кем-то другим ранее, и мне нужно сначала установить его. Поэтому, если вы можете думать об альтернативном и чистом способе делать это - это было бы здорово!

+4

Почему вы не используете ['DBI'] (https://metacpan.org/pod/DBI)? – TLP

+3

Это не основной вопрос. – mob

+0

@TLP: Могу ли я подключиться к серверу MSSQL с помощью DBI? – Deadman

ответ

2

@STD_IN = <STDIN> читает из дескриптора файла STDIN в контексте списка, то есть он будет блокироваться, пока не получит eof на дескрипторе файла. Функции IO::Select, с другой стороны, просто скажут вам, есть ли любой вход на выбранном дескрипторе файла, а не содержит ли он все входные данные.

Таким образом, в этом случае вы хотите прочитать STDIN в скалярном контексте (*). Это может выглядеть примерно так:

if ($s->can_read(.5)) { 
    push @STD_IN, scalar <STDIN>; 
    # check if there is more than one line of input ready ... 
    while ($s->can_read(0)) { 
     push @STD_IN, scalar <STDIN>; 
    } 
} 

(*) - здесь может быть недостаточно скалярного контекста. Скалярный контекст будет считываться с дескриптора файла до следующего конца строки или символьной последовательности. Для буферизованного ввода или неструктурированного ввода IO::Select может сообщить вам, что вход доступен, но этот вход может не содержать новую строку, а вызов scalar <STDIN> будет блокироваться. В этом случае вам, возможно, придется прибегать к загрузке ввода одного символа за раз (с getc или read/sysread) или, если ваша ОС поддерживает его, настройку неблокирующего дескриптора файла.

1

Этот код (условно) пытается читать со стандартного ввода, то есть вы, где он говорит <STDIN>. «Висеть» ждет, когда вы наберете что-нибудь. Или, скорее всего, этот код был спроектирован так, чтобы в него что-то попало. Попробуйте ввести ctrl-d в следующий раз, когда он «зависает», чтобы проверить.

+0

Ну, в документации говорится, что если вы укажете значение тайм-аута, оно не будет висеть – Deadman

+0

Это не 'can_read', а« зависание ». Это ''. –

0
./myscript "select * from mytable" 

Внутри двойные кавычки «*» расшифровывается Bash в список файлов в текущем каталоге. Используйте одинарные кавычки, чтобы использовать строку verbatim.

+0

Спасибо за предложение. Но я видел проблему, даже когда я делаю что-то вроде «select col1 from mytable». – Deadman

2

Возможно, он будет висел в ожидании STDIN, как это предполагали другие, но еще одна вещь, на которую нужно обратить внимание: вы уверены, что это не команда tsql, которая висит? Когда вы видите зависающий процесс perl, вы также видите зависающий процесс tsql?

С возвратом команда выполняется синхронно, а управление не возвращается к следующей строке вашего скрипта Perl до тех пор, пока эта команда не завершится. Так что, если это зависает, ваш скрипт perl тоже будет висеть, ожидая завершения этой системной команды tsql.

+0

Спасибо за указание, я проверил – Deadman

+0

Я проверил, tsql, похоже, не висит, когда Perl повешен. В частности, я не вижу tsql под выходом ps -ef. Так что, видимо, он действительно висел в STDIN – Deadman