1

I am currently using ProcessBuilder to run commands from a java server. This server is to replace an old Perl server, and a lot of our legacy code specifies platform specific command lines.

For instance, on windows it might do:

command -option "hello world"

and on unix it might do:

command -option 'hello world'

The problem is that ProcessBuilder and Runtime.exec both take in tokenized command lines (e.g., {"command", "-option", "hello world"} for both unix and windows).

While I prefer the platform independant way, we have somewhere in the range of 30 million lines of perl code in our codebase. Without me writing a tokenizer for the different platforms (not a big deal really, I just don't want to make a WTF), is there a way to let the shell on the operating system tokenize the command line?

asked Dec 30, 2009 at 15:16
3
  • command -option "hello world" works on unix as well, quotes are quotes... Commented Dec 30, 2009 at 15:21
  • Regardless, our code does conditionalize on windows vs. unix, usually because the commands are more complex than that and have nested quotes and command line variables and other such nonsense. Commented Dec 30, 2009 at 15:35
  • 30 million lines of perl?!? I'm so glad I'm not you ;) Commented Jun 28, 2012 at 20:42

2 Answers 2

7

Are you able to use the overloaded Runtime.exec(String) that takes a single String and runs that as the entire command?


The following works for me on Windows:

Process p = Runtime.getRuntime().exec("perl -e \"print 5\"");
System.out.println(IOUtils.toString(p.getInputStream()));
p.destroy();

This is more or less what Runtime.exec(String) is doing:

public static void main(String [] args) throws Exception {
 Process p = new ProcessBuilder(getCommand("perl -e \"print 5\"")).start();
 System.out.println(IOUtils.toString(p.getInputStream()));
 p.destroy();
}
private static String[] getCommand(String input) {
 StringTokenizer tokenizer = new StringTokenizer(input);
 String[] result = new String[tokenizer.countTokens()];
 for (int i = 0; tokenizer.hasMoreTokens(); i++) {
 result[i] = tokenizer.nextToken();
 }
 return result;
}
answered Dec 30, 2009 at 15:23
Sign up to request clarification or add additional context in comments.

4 Comments

Is Perl on the path for the environment that the process is executing in?
Oops, I just realized that I was using ProcessBuilder, not Runtime.exec().
Is there anyway to use Runtime.exec() without loosing the ability to redirect stderr to stdout?
It doesn't appear so. However, if you look under the covers for Runtime.exec(String), you'll see it is simply using a StringTokenizer to parse the arguments into an array and then passing that to ProcessBuilder. Perhaps you could do something similar
5

I think the quotes are being interpreted by the shell. Instead, put the command in a shell script:

$ cat temp.sh 
#!/bin/sh
perl -e "print 5"

and execute it:

import java.io.BufferedReader;
import java.io.InputStreamReader;
public class PBTest {
 public static void main(String[] args) {
 ProcessBuilder pb = new ProcessBuilder("./temp.sh");
 pb.redirectErrorStream(true);
 try {
 Process p = pb.start();
 String s;
 BufferedReader stdout = new BufferedReader (
 new InputStreamReader(p.getInputStream()));
 while ((s = stdout.readLine()) != null) {
 System.out.println(s);
 }
 System.out.println("Exit value: " + p.waitFor());
 p.getInputStream().close();
 p.getOutputStream().close();
 p.getErrorStream().close();
 } catch (Exception ex) {
 ex.printStackTrace();
 }
 }
}

Console:

5
Exit value: 0
answered Dec 30, 2009 at 16:01

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.