代码之家  ›  专栏  ›  技术社区  ›  Stephen Sorensen

如何将输入从Perl导入Java命令?

  •  6
  • Stephen Sorensen  · 技术社区  · 15 年前

    我需要通过Java程序运行一个字符串,然后检索输出。Java程序通过标准输入接受字符串。以下工作:

    my $output = `echo $string | java -jar java_program.jar`;
    

    有一个问题: $string 可能是任何事。对这个问题有什么好的解决办法吗?

    5 回复  |  直到 15 年前
        1
  •  6
  •   Ivan Nevostruev    15 年前

    我建议你看看 IPC::Run3 模块。它使用非常简单的接口并允许 STDERR STDOUT . 下面是一个小例子:

    use IPC::Run3;
    ## store command output here
    my ($cmd_out, $cmd_err);
    my $cmd_input = "put your input string here";
    run3([ 'java', '-jar', 'java_program.jar'], \$cmd_input, \$cmd_out, \$cmd_err);
    print "command output [$cmd_out] error [$cmd_err]\n";
    

    看见 comparation with other modules .

        2
  •  6
  •   Community CDub    7 年前

    如果您可以使用CPAN模块(我假设大多数人都可以),请看 Ivan's answer IPC::Run3 . 它应该能处理你需要的一切。

    如果你不能使用模块,这里有一些简单的方法。

    您可以使用管道进行输入,这样可以避免所有这些命令行引用问题:

    open PIPE, "| java -jar java_program.jar";
    print PIPE "$string";
    close(PIPE);
    

    不过,看起来您实际上需要命令的输出。你 能够 用类似的方法打开两个管道 IPC::Open2 (往返于java进程)但如果试图同时处理这两个管道,可能会使自己陷入死锁。

    通过将java输出到一个文件,然后从该文件读取,可以避免这种情况:

    open PIPE, "| java -jar java_program.jar > output.txt";
    print PIPE "$string";
    close(PIPE);
    
    open OUTPUT, "output.txt";
    while (my $line = <OUTPUT>) {
        # do something with $line
    }
    close(OUTPUT);
    

    另一个选择是以另一种方式做事。将$string放入临时文件,然后将其用作java的输入:

    open INPUT, "input.txt";
    print INPUT "$string";
    close(INPUT); 
    
    open OUTPUT, "java -jar java_program.jar < input.txt |";
    while (my $line = <OUTPUT>) {
        # do something with the output
    }
    close(OUTPUT);
    

    请注意,这不是处理临时文件的最佳方式;我刚用过 output.txt input.txt 为了简单起见。看这张照片 File::Temp docs 以各种更干净的方式创建更干净的临时文件。

        3
  •  2
  •   jsoverson    15 年前

    你调查过吗 IPC::Run

    与此类似的语法可能就是您要查找的语法:

    use IPC::Run qw( run );
    my $input = $string;
    my ($out, $err);
    run ["java -jar java_program.jar"], \$input, \$out, \$err;
    
        4
  •  2
  •   Greg Bacon    15 年前

    像shell一样创建管道。

    这是我们可怕的线索:

    my $str = "foo * ~ bar \0 baz *";
    

    我们将向后构建管道,因此首先收集Java程序的输出:

    my $pid1 = open my $fh1, "-|";
    die "$0: fork: $!" unless defined $pid1;
    
    if ($pid1) {
      # grab output from Java program
      while (<$fh1>) {
        chomp;
        my @c = unpack "C*" => $_;
        print "$_\n  => @c\n";
      }
    }
    

    "-|" open 操作人员

    如果使用命令打开管道 '-' 任何一个 '|-' '-|' 具有2参数(或1参数)形式的 open() fork 完成,以及的返回值 父进程中子进程的pid,以及 0 在子进程中,filehandle对于父进程的行为正常,但该filehandle的i/o通过管道从/到 STDOUT STDIN 子进程的定义。

    这个 unpack 可以窥视从管道读取的数据内容。

    在您的程序中,您希望运行Java程序,但下面的代码使用了合理的传真:

    else {
      my $pid2 = open my $fh2, "-|";
      die "$0: fork: $!" unless defined $pid2;
    
      if ($pid2) {
        $| = 1;
        open STDIN, "<&=" . fileno($fh2)
          or die "$0: dup: $!";
    
        # exec "java", "-jar", "java_program.jar";
    
        # simulate Java program
        exec "perl", "-pe", q(
          BEGIN { $" = "][" }
          my @a = split " ", scalar reverse $_;
          $_ = "[@a]\n";
        );
        die "$0: exec failed";
      }
    

    最后,谦逊的孙子只需打印可怕的字符串(到达Java程序的标准输入)并退出。背景 $| 为真值刷新当前选定的文件句柄并将其置于非缓冲模式。

      else {
        print $str;
        $| = 1;
        exit 0;
      }
    }
    

    其产出:

    $ ./try
    [*][zab][][rab][~][*][oof]
      => 91 42 93 91 122 97 98 93 91 0 93 91 114 97 98 93 91 126 93 91 42 93 91 111 111 102 93
    

        5
  •  1
  •   Stephen Sorensen    15 年前

    内置IPC::Open2模块提供了一个无需外部文件即可处理双向管道的功能。