Как я могу передать ввод в команду Java от Perl? - PullRequest
6 голосов
/ 15 декабря 2009

Мне нужно запустить строку через программу Java, а затем получить вывод. Программа Java принимает строку через стандартный ввод. Следующие работы:

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

Есть одна проблема: $string может быть чем угодно. Есть мысли о хорошем решении этой проблемы?

Ответы [ 5 ]

6 голосов
/ 15 декабря 2009

Предлагаю посмотреть на 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";

См. IPC::Run3 Сравнение с другими модулями .

6 голосов
/ 15 декабря 2009

Если вы можете использовать модули CPAN (а я полагаю, что большинство людей могут), посмотрите на ответ Ивана об использовании 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 , чтобы найти более понятные способы более чистого создания временных файлов.

2 голосов
/ 15 декабря 2009

Создайте конвейер, как ваша оболочка.

Вот наша страшная строка:

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 в дочернем процессе ... Файловый дескриптор ведет себя нормально для родительского процесса, но ввод / вывод для этого файлового дескриптора передается из / в STDOUT / STDIN дочернего процесса.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * unpack * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1030* * * * * * * * * * * * * * * * * * * * * * * * * * * *1030* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

В вашей программе вы захотите запустить программу на 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

Обратите внимание, что NUL выживает в поездке.

2 голосов
/ 15 декабря 2009

Вы смотрели в IPC::Run?

Синтаксис, подобный этому, может быть тем, что вы ищете:

use IPC::Run qw( run );
my $input = $string;
my ($out, $err);
run ["java -jar java_program.jar"], \$input, \$out, \$err;
1 голос
/ 15 декабря 2009

Встроенный модуль IPC :: Open2 предоставляет функцию для обработки двунаправленного трубопровода без внешнего файла.

...