Perl select 函数无限期挂起

Perl select function hanging indefinitely

对于这个非常基本的问题,我深表歉意,但我似乎没有找到问题的根本原因。

环境详情: Perl 5.14.1 通过 freeTDS tsql 连接到 MS SQL 服务器 Linuxx64

这是我的代码:

#!/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"

它有时工作正常,但我经常看到脚本不确定地挂起。

我通过 运行ning 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: 由于一些限制,一些变量、文件名和其他内容已从原始文件中修改。 另外,这个脚本是以前别人写的,我需要先修复挂起。因此,如果您能想到替代和干净的方式来执行此操作 - 那就太好了!

@STD_IN = <STDIN> 从列表上下文中的文件句柄 STDIN 读取,这意味着它会阻塞,直到它在文件句柄上收到 eof。另一方面,IO::Select 的函数只会告诉您所选文件句柄上是否有 any 输入,而不是它是否包含所有输入。

所以在这种情况下,您想在标量上下文 (*) 中读取 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),或者,如果您的 OS 支持它,则设置一个非阻塞的文件句柄。

此代码(有条件地)尝试从标准输入(即您)读取<STDIN>。 "hang" 正在等待您输入内容。或者更可能的是,此代码旨在将某些内容通过管道传输到其中。下次尝试输入 ctrl-d "hangs" 来验证。

./myscript "select * from mytable"

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

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

使用反引号,命令是 运行 同步的,在该命令完成之前,控制权不会交还给 Perl 脚本的下一行。因此,如果挂起,您的 perl 脚本也会挂起,等待 tsql 系统命令完成。