你好,我是一名Java新手。

我目前正在建立一个Java应用程序,用Java Process builder执行多个Linux命令。

我打算执行一个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文件,但它似乎是空的,而且无论我设置多长时间的睡眠,程序似乎都会立即返回打印语句。

如果有人能告诉我我做错了什么,我真的很感激。

提前感谢你!!!。

2 个评论
VGR
You should use redirectOutput而不是让bash命令来做。 不要在启动你的进程后立即调用start.destroy();首先让进程通过调用start.waitFor()完成。
@VGR 谢谢你的反馈。然而,是否有办法在同一过程中输入q,因为我需要在该过程结束后关闭程序。
java
linux
sleep
processbuilder
user17085185
发布于 2021-10-25
2 个回答
arp5
arp5
发布于 2021-10-25
0 人赞同

正如@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()来获得一个你可以写入的输出流,以便将数据输送到进程的stdin。如果你把"q\n"写进去,它应该和用户输入q并点击回车键一样。
@thatotherguy 谢谢你的反馈,但我对如何执行你说的有点不清楚。我尝试了start.getOutPutStream("q\n"),但似乎该方法不接受字符串。
@Adam 它不接受任何参数,并返回一个OutputStream。见docs.oracle.com/javase/tutorial/essential/io关于如何在Java中使用IO流的问题
VGR
VGR
发布于 2021-10-25
0 人赞同

你的大部分问题都是由于对流程的工作原理的误解。 这些概念不是Java的概念,你在任何其他语言中都会有同样的问题。

首先,你是在进程运行之前就破坏了它,甚至可能在它开始之前就破坏了。 这是因为pb.start()启动了进程,然后你立即破坏它,不给它一个完成的机会。

你应该根本不需要破坏这个过程。 只要让它完成。

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

所有进程都有自己的标准输入标准输出。 Again, this is not a Java concept; this has been a fundamental feature in Unix和Windows operating systems for a long time.

Normally, when a process prints information by writing it to its 标准输出。 That is in fact what Java’s System.out.println does. In Unix shells (and in Windows), the > character redirects the standard output of a process to a file; the program still writes to its standard output, without ever knowing that the operating system is sending that output to a destination other than the terminal. Since it’s a fundamental operating system function, Java can do it for you:

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

Similarly, when a process wants to take input, it normally does so by reading from its 标准输入. This is not the same as executing another command. When you do this:

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

你不是在向shell脚本发送q。 上述命令等到shell脚本完成。然后执行一个睡眠,然后尝试执行一个名为q的程序(这个程序可能不存在)。

Since the test_elanprv2.2.sh shell script probably accepts commands by reading its 标准输入, you want to send the q command to the 标准输入 of that process:

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");