【发布时间】:2015-10-08 22:07:16
【问题描述】:
我有一个标量,我想输入 open3 作为输入。例如
my $sql = "select * from table;";
open( SQL, "<", \$sql );
my ($output);
open3( '<&SQL', $output, $output, "mysql -h 127.0.0.1" );
但是,open3 位于不同的模块中:
package main;
use Example::Runner;
my $sql = "select * from table;";
open( my $in_handle, "<", \$sql );
my ($out_handle);
Example::Runner::run( $in_handle, $out_handle, $out_handle
'mysql -h 127.0.0.1' );
然后在另一个文件中:
package Example::Runner;
sub run {
my ($in, $out, $err, @command) = @_;
open3( ?, $out, $err, "mysql -h 127.0.0.1" );
}
问题是,在Example::Runner 中,我有一个可以从<$in> 读取的参考,但我需要的是我可以在'<&' 前加上前缀,以便open3 将其用作命令的STDIN它执行。知道如何将句柄的引用转换为 open3 可以用于其STDIN 的东西吗?
编辑:
很明显,我的人为示例还不够……我不直接使用 {{DBI}} 的原因是这段代码实际上是我用于 footprintless 自动化。换句话说,我有一个由 30 多台服务器组成的环境,我的管理员没有安装任何特殊工具(只是 RHEL 5/6 中的标准工具)。这些服务器分为服务器集(db、app、web),用于每个环境(本地、dev、qa、beta、prod),用于每个项目(...)。无论如何,一项非常常见的任务是将数据库从一个地方复制到另一个地方。我们使用类似于以下的命令来完成此操作:
use IPC::Open3::Callback::CommandRunner;
use IPC::Open3::Callback::Command qw(command pipe_command);
my $source_config = {hostname => 'proj1-prod-db', sudo_username => 'db'};
my $dest_config = {hostname => 'proj1-prod-db', sudo_username => 'db'};
my $command_runner = IPC::Open3::Callback::CommandRunner->new();
$command_runner->run_or_die( pipe_command(
command( "mysqldump dbname", $source_config ),
command( "mysql dbname", $dest_config ) ) );
# runs: ssh proj1-prod-db "sudo -u db mysqldump dbname" | ssh proj1-dev-db "sudo -u db mysql dbname"
这是MOST 将我们的生产数据库克隆回开发环境的基本版本(更典型的版本包括每个命令上的许多开关和中间的许多管道命令)。所以,我围绕这个(IPC::Open3::Callback::*)编写了一个抽象库。在此过程中,我们遇到了需要执行一些在复制数据库后需要运行的 SQL 命令。因此,我们添加了运行任意 SQL 脚本集的功能(基于克隆操作的源和目标)。我可以用这样的命令运行它们:
$command_runner->run_or_die( pipe_command(
"cat $post_restore",
command( "mysql dbname", $dest_config ) ) );
但是我遇到了一些 SQL 脚本内容的需求,所以我想把它吞进去,做一些工作,然后提供给$command_runner作为STDIN。也就是说,我尝试使用fileno 来处理这个问题:
sub safe_open3_with {
my ($in_handle, $out_handle, $err_handle, @command) = @_;
my @args = (
$in_handle ? '<&' . fileno( $in_handle ) : undef,
$out_handle ? '>&' . fileno( $out_handle ) : undef,
$err_handle ? '>&' . fileno( $err_handle ) : undef,
@command
);
return ( $^O =~ /MSWin32/ ) ? _win_open3(@args) : _nix_open3(@args);
}
但是如果$in_handle 是一个标量引用,它就不起作用。总之,说来话长。
【问题讨论】:
-
我不确定我是否理解。为什么你不能给它一个句柄然后打印到那个句柄?
my $pid = open3( \*SQL, $output, $output, "mysql -h 127.0.0.1" );if($pid){print SQL (<WHATEVERYOUREADIN>);close(SQL);} -
或保留您原来的
SQL并执行open (\*SQL2,$output,$output,...);print SQL2 <SQL>; close SQL2; -
@hepcat72,@mob,我试图简化这个例子中的问题,但原因是它必须在 在命令开始运行之前或@987654340 @我用来处理 OUT 和 ERR(以及 IN ish)变得很不稳定。 (这是给
IO::Open3::Callback::safe_open_3)... -
使用 IPC::Open3 无法做到这一点。使用 IPC::Run 获得更灵活的接口,它还支持输入/输出的标量和函数。
-
也许我不明白你到底想做什么,但为什么不使用 DBI?