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

发布于 2025-01-06 04:39:02 字数 4444 浏览 0 评论 0原文

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

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

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

当这不起作用时,我尝试执行system()。那不起作用,所以最后,我使用 system("JAVA_HOME=/path/to/java && /path/to/java_program"); 让它工作;

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

#!/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");

这是运行 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.

以及第一个 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.

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

    -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

最后解决问题:除了有要设置与 system() 调用一致的环境,将环境变量传递给 IPC::Run3 或 system() 调用的适当方法是什么?

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

如果相关:

-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

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.

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

Assuming IPC::Run3 would use %ENV, I tried adding $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");

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:

    -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:

    -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?

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蔚蓝源自深海 2025-01-13 04:39:02

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

已修订

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

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

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

  • 包装器使用了错误的类名。类名“nutch”不寻常且可疑 - 没有包名称。

真正的根本原因似乎是您错误地组装了参数列表。每个内部有空格的参数实际上应该是两个参数;即

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

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

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

REVISED

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

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文