Executing untokenized command line from Java

2019-03-01 23:30发布

问题:

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?

回答1:

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;
}


回答2:

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