2

I am trying to write a Perl script to bring up a Postgres client once and send several files through the client, captures the output separately for each file.

If I do something like:

system ("cat $query1.sql | psql -p 2070 super &> $HOME/Results1.txt");
system ("cat $query2.sql | psql -p 2070 super &> $HOME/Results2.txt");

then Perl will start up the client for each query. As I'll be running hundreds and maybe thousands of queries I want to skip the overhead for starting up all but the first client.

I think I should be able to bring up the Postgres client via Open2, but it hangs when I try. I'm doing this on SUSE Linux machine with Perl 5.10.0.

Here's my code:

use IPC::Open2;

use IO::Handle;

our $pid = open2(*CHILDOUT, *CHILDINT, '../installdir/bin/psql -p 2070 super');
print STDOUT $pid;

print CHILDINT "cat $dumpR5KScript";
print STDOUT 'Sent the commands';

$output = <CHILDOUT>;

close(CHILDIN);
close(CHILDOUT);

It appears to be hanging with "open2" because I never see the pid.

Can someone point out what I am doing wrong so my call to open2 doesn't hang?

And if anyone has advice on the larger issue of the best way of bringing up a Postgres client and running queries through it I would be grateful.

4

1 回答 1

1

您已经被告知在您的帖子的评论中使用 DBI,如果您这样做将是一件好事。格式化比摆弄 IPC 和在 Perl 和命令行数据库客户端之间拼接一种 API、解析输出和格式化输入要容易得多

但是,关于您的问题:

  1. 它应该\*CHILDIN代替*CHILDIN(引用 typeglob 而不是 typeglob)

  2. 无论如何,在这种情况下,您应该使用变量而不是 typeglobs 和古老的成语:

    my ( $childout, $childin ) ;
    our $pid = open2( $childout, $childin, '../installdir/bin/psql -p 2070 super');
    print STDOUT $pid;
    
  3. 请阅读IPC::Open2的文档。

  4. 此外,最好使用open3来处理 STDERR

  5. 最后,我不知道 postgress 客户端,但是 open2 出现死锁的可能性(你正在经历)是非常真实的:

这整个事件是非常危险的,因为你可能会永远阻止。它假设它将与 bc 之类的东西交谈,既向它写入数据,又从中读取数据。这大概是安全的,因为您“知道”像 bc 这样的命令将一次读取一行并一次输出一行。然而,像 sort 这样的程序首先读取整个输入流,很容易导致死锁。

这种方法的最大问题是,如果您无法控制在子进程中运行的源代码,您就无法控制它对管道缓冲的作用。因此,您不能只打开一个到 cat -v 的管道并不断地从中读取和写入一行。

CPAN 的 IO::Pty 和 Expect 模块可以帮助解决这个问题,因为它们提供了一个真正的 tty(实际上是一个伪 tty),它可以让您再次回到调用命令中的行缓冲。

于 2012-10-12T08:59:39.410 回答