Perl选择函数无限期挂起

时间:2015-09-28 18:21:32

标签: perl freetds

我很抱歉这个非常基本的问题,但我似乎找不到问题的根本原因。

环境详情: Perl 5.14.1 通过freeTDS tsql连接到MS SQL Server 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\n@ARGV";

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

在这里挂起的原因是什么?我还不明白 - 这是一个非常简单的剧本。

我检查了IO :: Select的perl文档,这就是它所说的 -

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 个答案:

答案 0 :(得分: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>调用将阻止。在这种情况下,您可能不得不求助于一次加载一个字符(getcread/sysread),或者,如果您的操作系统支持,则设置一个非阻塞文件句柄。

答案 1 :(得分:2)

可能会像其他人建议的那样挂起等待STDIN,但还有另外一件事要研究:你确定它不是挂起的tsql命令吗?当你看到一个挂起的perl进程时,你是否也看到了一个挂起的tsql进程?

使用反引号,该命令可以同步运行,并且在该命令完成之前,控制权不会返回到Perl脚本的下一行。所以如果挂起,你的perl脚本也会挂起,等待tsql系统命令完成。

答案 2 :(得分:1)

此代码(有条件地)尝试从标准输入读取,即您在<STDIN>所在的位置读取。 &#34;挂起&#34;正在等你输入一些东西。或者更有可能的是,这段代码的设计目的是通过管道输入。尝试下次输入ctrl-d&#34;挂起&#34;,进行验证。

答案 3 :(得分:0)

./myscript "select * from mytable"

内部双引号“*”由Bash扩展为当前目录中的文件列表。使用单引号逐字使用字符串。