如何从Perl管道输入到Java命令?

时间:2009-12-15 18:05:38

标签: perl command pipe

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

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

有一个问题:$string几乎可以解决任何问题。有关解决这个问题的任何想法吗?

5 个答案:

答案 0 :(得分:6)

如果您可以使用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.txtinput.txt。查看File::Temp docs以获得更清晰地创建临时文件的各种更简洁的方法。

答案 1 :(得分:6)

我建议您查看IPC::Run3模块。它使用非常简单的界面,允许获得STDERRSTDOUT。这是一个小例子:

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";

请参阅IPC::Run3 comparation with other modules

答案 2 :(得分:2)

你有没有看过IPC::Run

您可能正在寻找与此类似的语法:

use IPC::Run qw( run );
my $input = $string;
my ($out, $err);
run ["java -jar java_program.jar"], \$input, \$out, \$err;

答案 3 :(得分:2)

像你的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";
  }
}

请注意Perl的open运算符的特殊"-|"参数。

  

如果您在命令'-'上打开管道,则'|-''-|'具有2个参数(或1个参数)形式open(),然后有一个隐式fork完成,open的返回值是父进程中子进程的pid,以及子进程中的0 ...文件句柄对于父文件正常运行,但该文件句柄的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程序的标准输入)并退出。将$|设置为true值会刷新当前选定的文件句柄并将其置于无缓冲模式。

  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

请注意,NUL在旅行中幸存下来。

答案 4 :(得分:1)

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