maithree has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
I'm invoking a java app from within my perl script on windows using backticks since I need to capture the output. The classpath contains spaces in the directory names like "C:\Program Files\ABC". Whenever I run this script, I get the error
Exception in thread "main" java.lang.NoClassDefFoundError: Files/ABC
This is clearly due to the spaces. I've tried enclosing the classpath within quotes but the problem doesnt go away. When I execute the same command using system(), it works just fine.
The same error occurs when using open(FILE,"$cmd|") where $cmd is the java command which includes the classpath in the arguments to java.
Any help in this is appreciated.
Thanks.

Replies are listed 'Best First'.
Re: CLASSPATH problem when using backticks
by ikegami (Patriarch) on May 21, 2008 at 18:08 UTC
    It's hard to tell why your command isn't being interpreted as you desire without seeing the command (print("[$cmd]\n");). Furthermore, the suitability of a solution would be enhanced by having the code that builds your command.
Re: CLASSPATH problem when using backticks
by pc88mxer (Vicar) on May 21, 2008 at 17:36 UTC
    What you need is a way to capture the output from the java app without invoking an intermediate shell. Then your command line arguments will not get re-interpreted. A good standard module for this is IPC::Open3. Try something like this:
    use IPC::Open3; sub backticks { my $pid = open3(my $wfh, my $rfh, 0, @_) or die "open3 failed: $!"; close($wfh); # assume the script needs no input my $output; while (<$rfh>) { $output .= $_ } close($rfh); $output; } my $java_output = backticks('java', '--classpath=...', ...);

      No need for open3.

      sub backticks { open(my $pipe, '-|', @_) or return; local $/ = wantarray ? $/ : undef; <$pipe> } my $java_output = backticks('java', '--classpath=...', ...);

      Bonus: Handles context and errors just like the real thing.

        Is this available in a standard module? If not, I think it should be. The situation seems to comes up enough. I'd like to deprecate all calls to exec which invoke an intermediate shell and replace them with safer alternatives.

        Update: Banning all use of the single-argument forms of exec, system, etc. is probably too draconian. The real problem occurs when a variable is interpolated in that single argument, e.g. my $output = `command $arg`. Perhaps this is something that Perl::Critic can look for and advise that a safer way should be sought to perform the operation.

Re: CLASSPATH problem when using backticks
by pc88mxer (Vicar) on May 21, 2008 at 18:28 UTC
    Another option is to see if you can pass the classpath setting in an environment variable:
    $ENV{CLASSPATH} = ...; my $output = `java ...`; # no need to specify -classpath here
      Thanks all for responding. The error given by java was actually misleading. Though the error mentioned ClassNotFound, the actual issue was in one of the command line parameters which also had a space in it. When I put that in quotes, I got the expected behaviour.

        the actual issue was in one of the command line parameters which also had a space in it.

        We know. That's what all the solutions we provided addressed. Adding quotes is actually a rather poor solution. The solutions provided go beyond adding quotes and avoid the need for quoting and escaping completely. That's much safer and reliable.