【问题标题】:Java Process Builder not executing multiple commandsJava Process Builder 不执行多个命令
【发布时间】:2021-12-10 13:32:55
【问题描述】:

您好,这里是 Java 新手。

我目前正在构建一个使用 Java Process builder 执行多个 linux 命令的 Java 应用程序。

我打算执行一个 shell scipt,由于这个 shell 脚本是一个外部程序,需要大约一秒钟才能完全执行,所以让进程休眠一秒钟并将结果写入一个 txt 文件。

这是一个外部程序,必须输入“q”才能退出程序,所以我最后需要在终端输入q。

我之前在这个社区得到过帮助,我用那个帮助构建的代码如下。

public static void Linux(String fileName){

try {
  File dir = new File("/usr/local/bin");
  ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "./test_elanprv2.2.sh > \"$1\"; sleep 1; q", "_", fileName + ".txt"});
  System.out.println("wrote text");
  pb.directory(dir);
  Process start = pb.start();
  start.destroy();
}catch (Exception e){
  e.printStackTrace();
  System.out.println("failed to write text");
}

进程构建器确实创建了一个 txt 文件,但它似乎是空的,而且无论我将睡眠设置为多长时间,程序似乎都会立即返回打印语句。

如果有人能告诉我我做错了什么,我将不胜感激。

提前谢谢你!!

【问题讨论】:

  • 您应该使用redirectOutput 而不是让 bash 命令执行此操作。并且不要在启动进程后立即调用 start.destroy();让进程完成,首先调用start.waitFor()
  • @VGR 感谢您的反馈。但是有没有办法将 q 输入到同一个进程中,因为我需要在进程完成后关闭程序。

标签: java linux sleep processbuilder


【解决方案1】:

正如@VGR 所说,尝试使用redirectOutput

public static void Linux(String fileName){

try {
   File dir = new File("/usr/local/bin");
   ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "./test_elanprv2.2.sh");
   File output = new File("_", fileName + ".txt");
   pb.redirectOutput(output);
   System.out.println("wrote text");
   pb.directory(dir);
   Process start = pb.start();
   start.destroy();
} catch (Exception e) {
   e.printStackTrace();
   System.out.println("failed to write text");
}

【讨论】:

  • 非常感谢您的反馈!但是有没有办法在同一个过程中输入“q”?我试过用 cntrl + c 手动退出程序,但这似乎会给程序造成一些错误,应该输入一个 q 才能正确退出程序。
  • 您可以在进程上使用getOutputStream() 来获取可以写入的输出流,以便将数据通过管道传输到进程的标准输入。如果你给它写"q\n",它应该和用户输入q然后回车一样。
  • @thatotherguy 感谢您的反馈,但我有点不清楚如何执行您所说的。我试过 start.getOutPutStream("q\n") 但似乎该方法不接受字符串。
  • @Adam 不带参数,返回一个OutputStream。请参阅docs.oracle.com/javase/tutorial/essential/io 了解如何在 Java 中使用 IO 流
【解决方案2】:

您的大部分问题是由于对流程的工作方式存在误解。这些概念不是 Java 概念;用任何其他语言你都会遇到同样的问题。

首先,您在进程运行之前,甚至可能在它开始之前就破坏了它。这是因为pb.start() 启动了该过程,然后您立即将其销毁,而没有给它完成的机会。

您根本不需要破坏进程。让它完成:

Process start = pb.start();
start.waitFor();

所有进程都有自己的标准输入标准输出。同样,这不是Java概念;长期以来,这一直是 Unix 和 Windows 操作系统的基本功能。

通常,当进程通过将信息写入其标准输出来打印信息时。这实际上是 Java 的 System.out.println 所做的。在 Unix shell(和 Windows)中,> 字符将进程的标准输出重定向到文件;程序仍会写入其标准输出,而并不知道操作系统正在将该输出发送到终端以外的目的地。由于它是一个基本的操作系统功能,Java 可以为您完成:

ProcessBuilder pb =
    new ProcessBuilder("/bin/bash", "-c", "./test_elanprv2.2.sh");
pb.redirectOutput(new File(fileName + ".txt"));

同样,当一个进程想要获取输入时,它通常通过读取其标准输入来实现。这与执行另一个命令不同。当你这样做时:

./test_elanprv2.2.sh > "$1"; sleep 1; q

您没有将q 发送到shell 脚本。上述命令等待shell脚本完成,然后执行休眠,然后尝试执行名为q的程序(可能不存在)。

由于 test_elanprv2.2.sh shell 脚本可能通过读取其标准输入来接受命令,因此您希望将q 命令发送到该进程的标准输入:

ProcessBuilder pb =
    new ProcessBuilder("/bin/bash", "-c", "./test_elanprv2.2.sh");
pb.redirectOutput(new File(fileName + ".txt"));

Process start = pb.start();
Thread.sleep(1000);

try (Writer commands = new OutputStreamWriter(start.getOutputStream())) {
    commands.write("q\n");
}

// Caution: Call this AFTER writing commands.  You don't want to write
// to the standard input of a process that has already finished!
start.waitFor();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    • 1970-01-01
    • 2017-11-22
    相关资源
    最近更新 更多