我正在尝试编写一个Perl脚本来启动一个Postgres客户端并通过客户端发送多个文件,分别为每个文件捕获输出。
如果我这样做:
system ("cat $query1.sql | psql -p 2070 super &> $HOME/Results1.txt");
system ("cat $query2.sql | psql -p 2070 super &> $HOME/Results2.txt");
然后Perl将为每个查询启动客户端。由于我将运行数百甚至数千个查询,因此我希望跳过启动除第一个客户端以外的所有开销。
我想我应该可以通过Open2启动Postgres客户端,但是当我尝试时它会挂起。我在使用Perl 5.10.0的SUSE Linux机器上执行此操作。
这是我的代码:
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);
似乎挂着“open2”,因为我从未见过这个pid。
有人可以指出我做错了什么,所以我对open2的调用没有挂起吗?
如果有人就提出Postgres客户端并通过它运行查询的最佳方式提出建议,我将不胜感激。
答案 0 :(得分:1)
您已经被告知在帖子的评论中使用DBI,如果您这样做,这将是一件好事。格式化很多比摆弄IPC更容易,并在Perl和命令行数据库客户端之间拼接一种API,解析输出并格式化输入。
关于你的问题,但是:
\*CHILDIN
而不是*CHILDIN
(引用typeglob而不是typeglob)无论如何在这种情况下你应该使用变量而不是typeglobs和古代习语:
my ( $childout, $childin ) ;
our $pid = open2( $childout, $childin, '../installdir/bin/psql -p 2070 super');
print STDOUT $pid;
这整个事件非常危险,因为你可能永远阻止。它假设它会与bc这样的东西交谈,既写入它又从中读取。这可能是安全的,因为你“知道”像bc这样的命令会一次读取一行并一次输出一行。然而,首先读取整个输入流的排序等程序很容易导致死锁。
这种方法的一个大问题是,如果您无法控制在子进程中运行的源代码,则无法控制它对管道缓冲的作用。因此,你不能只打开一个管道来管理-v并不断地从中读取和写入一行。
CPAN的IO :: Pty和Expect模块可以帮助解决这个问题,因为它们提供了一个真正的tty(实际上是伪tty),它可以让你再次回到被调用命令的行缓冲。