1

我试图让这个 Perl 代码正常工作,我相信我只需要正确地引用我的引用。对于如何使用引用的任何反馈,我将不胜感激,但如果在没有 API 更改的情况下无法使此代码工作,我还将感谢有关如何更改周围 API 以支持我需要的数据类型的反馈。

我正在尝试向 PostgreSQL 测试套件添加一个新测试。有问题的代码运行一个子进程并将进程参数存储在散列中的数组文字中。例如:

my %pgdump_runs = (
    defaults => {
        dump_cmd => [
            'pg_dump', '--no-sync',
            '-f',      "$tempdir/defaults.sql",
            'postgres',
        ],
    },
    # and others
)

该数组被传递给一个辅助库,如下所示:

    $node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} },
        "$run: pg_dump runs");

辅助库不断向下传递数组:

sub command_ok
{
    my ($cmd, $test_name) = @_;
    my $result = run_log($cmd);

然后最后调用IPC::Run

sub run_log
{
    return IPC::Run::run(@_);
}

要编写我的测试用例,我必须将命令的输出通过管道传输到不支持查找的文件描述符。看起来 IPC::Run 模块为您支持管道。这是文档的示例:

run \@cmd1, '|', \@cmd2;

但是我尝试了很多不同的方法来尝试构建我的数组文字,但都没有奏效。例如,我试过这个,我相信它给了我一个ARRAY(0xFFFFFFFF)错误:

        dump_cmd => [
            ['pg_dump', 'db'],
            '|',
            ['pg_restore', 'db2'],
        ],

如何获取此代码以使用管道设置多个子流程?

更新:我尝试了 ikegami 的建议:该command_ok函数只能有两个参数传递给它,所以这不起作用(你必须为第一个参数传递一个数组引用)。

更新:打开 IPC:Run 的调试功能我可以看到它是如何试图解释我的命令行的。它不是取消对数组的引用,而是尝试将其字符串化(?)并将该字符串作为可执行文件执行:

1070 IPC::Run 0002 01234567890- [#11(59856)]: parsing [ 'ARRAY(0x7ff3016f1090)', '|', 'ARRAY(0x7ff3016f1510)', '>/Users/david/src/pg_bug/postgres/foo' ]
4

1 回答 1

1

您正在有效地执行以下操作:[1]

my %pgdump_runs = (
    foo => {
        dump_cmd => [
            ['pg_dump', 'db'],
            '|',
            ['pg_restore', 'db2'],
        ],
    },
);

IPC::Run::run( $pgdump_runs{foo}{dump_cmd} )

这会将单个参数传递给run,但您表示您想要实现类似于

run \@cmd1, '|', \@cmd2;

那将需要

IPC::Run::run( @{ $pgdump_runs{foo}{dump_cmd} } )

有几种方法可以解决这个问题:

  1. 代替

    return IPC::Run::run(@_);
    

    return IPC::Run::run(@{ $_[0] });
    
  2. 代替

    run_log($cmd);
    

    run_log(@$cmd);
    
  3. 代替

    sub command_ok {
        my ($cmd, $test_name) = @_;
        my $result = run_log($cmd);
    }
    
    $node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs");
    

    sub command_ok {
        my $test_name = shift;
        my $result = run_log(@_);
    }
    
    $node->command_ok("$run: pg_dump runs", @{ $pgdump_runs{$run}{dump_cmd} });
    
  4. 代替

    dump_cmd => [
        ['pg_dump', 'db'],
        '|',
        ['pg_restore', 'db2'],
    ],
    

    use String::ShellQuote qw( shell_quote );
    
    dump_cmd => join(' ',
        shell_quote('pg_dump', 'db'),
        '|',
        shell_quote('pg_restore', 'db2'),
    ),
    

脚注:

  1. 除非你试图自动激活(你不是),

    \@{ $pgdump_runs{$run}->{dump_cmd} }
    

    也可以写成

    $pgdump_runs{$run}->{dump_cmd}
    

    在这两种情况下,->都可以省略,因为它位于两个索引之间。

于 2020-05-29T17:00:49.670 回答