从perl调用system()或IPC :: Run3命令似乎没有传递环境变量($ ENV {JAVA_HOME})

时间:2022-10-18 14:35:25

I've been struggling with launching a java process from perl. The root of the problem is that the java process is missing the JAVA_HOME environment variable causing a ClassNotFoundException.

我一直在努力从perl启动java进程。问题的根源是java进程缺少导致ClassNotFoundException的JAVA_HOME环境变量。

I started by using IPC::Run3 because of its relatively elegant redirection of STDIN/STDOUT.

我开始使用IPC :: Run3,因为它相对优雅的STDIN / STDOUT重定向。

Assuming IPC::Run3 would use %ENV, I tried adding $ENV{JAVA_HOME}.

假设IPC :: Run3将使用%ENV,我尝试添加$ ENV {JAVA_HOME}。

When that didn't work I tried doing system(). That didn't work, so finally, I got it to work using system("JAVA_HOME=/path/to/java && /path/to/java_program");

当这不起作用我尝试做system()。这没用,所以最后,我让它使用system(“JAVA_HOME = / path / to / java && / path / to / java_program”)工作;

My test program is below. Naturally I'd uncomment the proper block to test the appropriate invocation.

我的测试程序如下。当然,我会取消注释正确的块以测试适当的调用。

#!/usr/bin/perl -w
use strict;

use IPC::Run3;

use vars qw(%Config $nutch_stdout $nutch_stderr);

%Config = (
  'nutch_binary'       => q[/home/crawl/nutch/runtime/local/bin/nutch],
  'nutch_crawl_dir'    => q[/home/crawl/nutch-crawl/crawl/crawldb/current/part-00000],
  'nutch_seed_dir'     => q[/home/crawl/urls],
  'solr_url'           => q[http://localhost:8080/solr],
);

my @nutch_command = ("$Config{nutch_binary}",
                 "crawl $Config{nutch_seed_dir}",
                 "-solr $Config{solr_url}",
                 "-d    $Config{nutch_crawl_dir}",
                 "-threads 1",
                 "-depth 1");

$ENV{JAVA_HOME}       = '/usr/lib/jvm/java-1.6.0';

while ((my $key,my $value) = each %ENV) {
    print "$key=$value\n";
}

print "Running @nutch_command\n";

# My original code. Next few lines are shown in first batch of output below.
#run3 \@nutch_command, undef, \$nutch_stdout, \$nutch_stderr;
#print "Output from Nutch:\n";
#print $nutch_stdout;
#print "Errors from Nutch:\n";
#print $nutch_stderr;

# Second try. The next line's output is the second batch of output.
#system(@nutch_command);

# Third try. Despite setting and displaying %ENV, this is the only thing I tried that worked
system("JAVA_HOME=/usr/lib/jvm/java-1.6.0 && @nutch_command");

Here's the output of running the run3:

这是运行run3的输出:

    -bash-3.2$ ./test.pl 
    ... [snip] ...
    JAVA_HOME=/usr/lib/jvm/java-1.6.0
    ... [snip] ...
    Running /home/crawl/nutch/runtime/local/bin/nutch crawl /home/crawl/urls -solr http://localhost:8080/solr -d    /home/crawl/nutch-crawl/crawl/crawldb/current/part-00000 -threads 1 -depth 1
    Output from Nutch:
    Errors from Nutch:
    Exception in thread "main" java.lang.NoClassDefFoundError: crawl
    Caused by: java.lang.ClassNotFoundException: crawl
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
    Could not find the main class: crawl. Program will exit.

And the output of the first system() call:

并且第一个system()的输出调用:

    -bash-3.2$ ./test.pl
    ... [snip] ...
    JAVA_HOME=/usr/lib/jvm/java-1.6.0
    ... [snip] ...
    Running /home/crawl/nutch/runtime/local/bin/nutch crawl /home/crawl/urls -solr http://localhost:8080/solr -d    /home/crawl/nutch-crawl/crawl/crawldb/current/part-00000 -threads 1 -depth 1
    Exception in thread "main" java.lang.NoClassDefFoundError: crawl
    Caused by: java.lang.ClassNotFoundException: crawl
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
    Could not find the main class: crawl. Program will exit.

Finally, the third system call-- the only one that worked!-- with the environment variable set inline:

最后,第三个系统调用 - 唯一有效的! - 环境变量设置为内联:

    -bash-3.2$ ./test.pl
    ... [snip] ...
    JAVA_HOME=/usr/lib/jvm/java-1.6.0
    ... [snip] ...
    Running /home/crawl/nutch/runtime/local/bin/nutch crawl /home/crawl/urls -solr http://localhost:8080/solr -d    /home/crawl/nutch-crawl/crawl/crawldb/current/part-00000 -threads 1 -depth 1
    crawl started in: crawl-20120216133832
    ... continue success stdout output

Finally to the question: Aside from having to set the environment in-line with the system() call, what's the appropriate way to pass an environment var to a IPC::Run3 or a system() call?

最后的问题是:除了必须在system()调用中设置环境之外,将环境var传递给IPC :: Run3或system()调用的适当方法是什么?

(Note: output of %ENV is truncated to only relevant lines... lines like PATH, SHELL, _, etc. not relevant to the question omitted)

(注意:%ENV的输出被截断为仅相关的行......如PATH,SHELL,_等与省略的问题无关的行)

In case it's relevant:

如果相关:

-bash-3.2$ uname -a
Linux hostname 2.6.18-238.el5xen #1 SMP Thu Jan 13 16:41:45 EST 2011 x86_64 x86_64 x86_64 GNU/Linux
-bash-3.2$ perl --version
This is perl, v5.8.8 built for x86_64-linux-thread-multi

1 个解决方案

#1


0  

The root of the problem is that the java process is missing the JAVA_HOME environment variable causing a ClassNotFoundException.

问题的根源是java进程缺少导致ClassNotFoundException的JAVA_HOME环境变量。

REVISED

That is not the root of the problem. In fact, Java itself does not require JAVA_HOME to be set.

这不是问题的根源。实际上,Java本身不需要设置JAVA_HOME。

The immediate cause of the problem is one of the following:

问题的直接原因是以下之一:

  • The wrapper is not setting the classpath correctly for the application that you are trying to execute.

    包装器没有为您尝试执行的应用程序正确设置类路径。

  • The wrapper using the wrong class name. The class name "nutch" is unusual and suspicious - there's no package name.

    包装器使用错误的类名。班级名称“nutch”是不寻常和可疑的 - 没有包名。

It seems likely that the real root cause is that you are assembling the argument list incorrectly. Each of those arguments with a space inside them should really be two arguments; i.e.

似乎真正的根本原因是您正在错误地组装参数列表。每个带有空格的参数都应该是两个参数;即

        my @nutch_command = ("$Config{nutch_binary}",
             "crawl", "$Config{nutch_seed_dir}",
             "-solr", "$Config{solr_url}",
             "-d", "$Config{nutch_crawl_dir}",
             "-threads", "1",
             "-depth", "1");

I suspect that this has confused the nutch wrapper script, and caused it to use the wrong classname (among other things). When you pass the entire command as one string and let the shell parse it, the problem (naturally) goes away.

我怀疑这会混淆nutch包装器脚本,并导致它使用错误的类名(以及其他内容)。当您将整个命令作为一个字符串传递并让shell解析它时,问题(自然)就会消失。

#1


0  

The root of the problem is that the java process is missing the JAVA_HOME environment variable causing a ClassNotFoundException.

问题的根源是java进程缺少导致ClassNotFoundException的JAVA_HOME环境变量。

REVISED

That is not the root of the problem. In fact, Java itself does not require JAVA_HOME to be set.

这不是问题的根源。实际上,Java本身不需要设置JAVA_HOME。

The immediate cause of the problem is one of the following:

问题的直接原因是以下之一:

  • The wrapper is not setting the classpath correctly for the application that you are trying to execute.

    包装器没有为您尝试执行的应用程序正确设置类路径。

  • The wrapper using the wrong class name. The class name "nutch" is unusual and suspicious - there's no package name.

    包装器使用错误的类名。班级名称“nutch”是不寻常和可疑的 - 没有包名。

It seems likely that the real root cause is that you are assembling the argument list incorrectly. Each of those arguments with a space inside them should really be two arguments; i.e.

似乎真正的根本原因是您正在错误地组装参数列表。每个带有空格的参数都应该是两个参数;即

        my @nutch_command = ("$Config{nutch_binary}",
             "crawl", "$Config{nutch_seed_dir}",
             "-solr", "$Config{solr_url}",
             "-d", "$Config{nutch_crawl_dir}",
             "-threads", "1",
             "-depth", "1");

I suspect that this has confused the nutch wrapper script, and caused it to use the wrong classname (among other things). When you pass the entire command as one string and let the shell parse it, the problem (naturally) goes away.

我怀疑这会混淆nutch包装器脚本,并导致它使用错误的类名(以及其他内容)。当您将整个命令作为一个字符串传递并让shell解析它时,问题(自然)就会消失。