从Java代码获取cmd命令的输出

5

我有一个程序,我能够成功地从我的代码中执行cmd命令,但是我想能够获取cmd命令的输出。我该如何做呢?

到目前为止,我的代码是:

Second.java:

public class Second {
    public static void main(String[] args) {
        System.out.println("Hello world from Second.java");
    }
}

以及 Main.java

public class Main {
    public static void main(String[] args) {
        String filename = args[1].substring(0, args[1].length() - 5);
        String cmd1 = "javac " + args[1];
        String cmd2 = "java " + filename;

        Runtime r = Runtime.getRuntime();
        Process p = r.exec(cmd1); // i can verify this by being able to see Second.class and running it successfully
        p = r.exec(cmd2); // i need to see this output to see if 

        System.out.println("Done");
    }
}

我可以通过检查Second.class来确认第一个命令是否成功执行,但是如果该类生成了一些错误,我怎么能看到这些错误?

3个回答

9
您需要使用Process的OutputStream(InputStream),并且应该使用ProcessBuilder进行操作,如下所示。
public static void main(String[] args) {
  String filename = args[1].substring(0, args[1].length() - 5);
  String cmd1 = "javac " + args[1];
  String cmd2 = "java " + filename;

  try {
    // Use a ProcessBuilder
    ProcessBuilder pb = new ProcessBuilder(cmd1);

    Process p = pb.start();
    InputStream is = p.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    String line = null;
    while ((line = br.readLine()) != null) {
      System.out.println(line);
    }
    int r = p.waitFor(); // Let the process finish.
    if (r == 0) { // No error
       // run cmd2.
    }
  } catch (Exception e) {
    e.printStackTrace();
  }
}

我想在执行第二个命令时能够打印出错误信息。当我测试它时,它只会在编译和运行成功时输出结果,但是当我从Second.java中删除一个分号并运行Main.java时,它只给了我一个空的输出,而没有告诉我缺少分号,我应该添加什么来使它也能打印错误信息? - hakuna matata
这是真的吗?对于在PHP中可以写成“$output = command;”的东西,Java需要20行代码、一个进程构建器、一个缓冲读取器等等?这种过度抽象甚至不是全部故事--这段代码会泄露资源,因为流从未关闭... - TheOperator
@TheOperator,什么是真的吗?在 [tag:bash] 中,你可以写 output=$(command);不同的语言有不同的方式(例如,Java 不是一种 脚本 语言)。此外,在上面的示例中,资源会在 main 退出时关闭。 - Elliott Frisch
@ElliottFrisch Java 是否是脚本语言并不重要。完全可以将整个功能(调用系统命令并获取其输出)封装成一个方法,而不需要强制用户处理进程、缓冲读取器、循环、IO 异常和所有那些样板代码。关于资源,操作系统负责释放已关闭应用程序的文件句柄,而不是 Java。这种代码通常用于更复杂的应用程序,而不仅仅是一个 main() 方法--如果运行时间较长,则正确地释放系统资源非常重要。 - TheOperator
@TheOperator 你如何在C或C++中获取程序的输出?用户必须处理进程(popen(3)),(缓冲)读取器(fscanf),循环,IO异常甚至更多样板文件。使用Scala,您可以创建一个自定义DSL来像脚本语言一样包装此功能;但是这**是Java。 - Elliott Frisch
@ElliottFrisch 我不确定你在这里的观点是什么。因为其他一些语言也没有提供简单的方法,所以Java的方法已经足够好了吗?事实上,这种并不少见的需要功能可以包装在一个方法String exec(String command)throws IOException中,这表明这不是语言固有的问题,而是库/设计问题。更重要的是,在Java中,为了完成简单任务而使用荒谬复杂的结构常常被社区视为“前进的方向”,而不是受到质疑和潜在改进。 - TheOperator

4

一个常规的例子是从命令中获取返回结果:

 Process p = null;
    try {
        p = p = r.exec(cmd2);
        p.getOutputStream().close(); // close stdin of child

        InputStream processStdOutput = p.getInputStream();
        Reader r = new InputStreamReader(processStdOutput);
        BufferedReader br = new BufferedReader(r);
        String line;
        while ((line = br.readLine()) != null) {
             //System.out.println(line); // the output is here
        }

        p.waitFor();
    }
    catch (InterruptedException e) {
            ... 
    }
    catch (IOException e){
            ...
    }
    finally{
        if (p != null)
            p.destroy();
    }

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接