Java - 如何检测bash是否已返回?

时间:2016-02-14 01:09:52

标签: java linux bash shell process

我正在编写一个程序,我想在后台启动一个shell,并发送和接收输入和输出。我已经设法做到了这一点,并且可以成功读取和写入此过程。这是我遇到麻烦的地方。

我想在ShellManager(见下面的代码)中有一个方法,它等待进程完成/失败,并将输入返回给用户。

例如,如果我发送tar xzf something_that_will_take_a_while.tar.gz, 我可以在输出中看到它如何花费时间,然后回应:

]0;~
[32mMe@MyComputer [33m~[0m

我已经尝试阻止线程,直到收到]0;~,这不起作用。 (从未返回)

我也试过\u001B,同样的问题:(

我不确定这个符号是什么,并且在如何检测进程何时返回时找不到多少。

这是我的代码:

package buildSystem.shell;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import base.TermConstants;

public class ShellManager {
    private InputStream termOut;
    private OutputStream termIn;

    private ProcessBuilder build;
    private Process main;

    BufferedReader reader;
    BufferedWriter writer;

    public ShellManager() {
        build = new ProcessBuilder(TermConstants.getShellLocation());
        build.redirectErrorStream(true);    
    }

    public void start() throws IOException {
        try {
            main = build.start();
            termOut = main.getInputStream();
            termIn = main.getOutputStream();
            reader = new BufferedReader (new InputStreamReader(termOut));
            writer = new BufferedWriter(new OutputStreamWriter(termIn));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void writeLine(String s) throws IOException {
        writer.write(s);
        writer.newLine();
        writer.flush();
    }

    public String readNextLine() throws IOException {
        return reader.readLine();
    }

    public void end() {
        try {
            writeLine("exit\n");
            main.waitFor();
            termOut.close();
            termIn.close();
            reader.close();
            writer.close();
        } catch (IOException | InterruptedException e) {
            kill();
        }
    }

    public void kill() {
        main.destroyForcibly();
        try {
            termOut.close();
            termIn.close();
            reader.close();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

/*THE PART I AM HAVING TROUBLE WITH:*/

    public void waitForReturn() {
        try {
            while(reader.readLine() != "\u001B") {}
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

基本上,我想要一种可靠的方法来检测程序何时退出bash shell。 bash进程仍将运行,但从该bash实例运行的程序将返回。因此,我无法使用process.waitFor()

我尝试等待]0;~,然后等待[32mMe@MyComputer [33m~[0m,直到tar退出并出现错误代码,在这种情况下,两行将被反转。我不确定如何继续,因为检测到bash已经返回给用户应该是一个相对容易的任务。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

如果这代表了您尝试匹配输出的方式,那就是您的问题:

while(reader.readLine() != "\u001B") {}

除特殊情况外,您必须在equals()个实例上使用String方法:

while (true) {
  String line = reader.readLine();
  if ((line == null) || "\u001B".equals(line))
    break;
}

我不确定为什么你会在进程退出时期望ESC和换行符。

答案 1 :(得分:0)

我相信你需要调用Process.waitFor()方法。 所以你需要这样的东西:

Process p = build.start();
p.waitFor()

如果您正在尝试模拟bash shell,则允许输入命令,执行和处理输出而不会终止。有一个开源项目,可能是如何执行此操作的代码的良好参考。它可以在Git上找到。看一下Jediterm Pure Java Emulator。

考虑模拟bash,我也发现Piping between processes的这个例子也很重要。

它确实展示了如何提取正在执行的进程的输出,并将该数据作为输入传递给另一个Java进程。应该会有所帮助。