java - 如何使用 Java ProcessBuilder API 运行交互式 bash?

标签 java linux bash processbuilder jline

我正在尝试使用 java ProcessBuilder API 启动 bash:

代码:

public class BashExecutor {
    public void executeCommand(String[] command, Consumer<String> consumer) {
        ProcessBuilder processBuilder = new ProcessBuilder();
        processBuilder.command(command);
        processBuilder.redirectErrorStream(true);
        processBuilder.inheritIO();
        //processBuilder.redirectInput(ProcessBuilder.Redirect.PIPE);
        //processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        try {
            Process process = processBuilder.start();
            /*ProcessStreamConsumer streamConsumer = new ProcessStreamConsumer(process.getInputStream(), consumer);
            streamConsumer.consumeStream();*/
            process.waitFor();
            if(process.isAlive()){
                process.destroyForcibly();
            }
        } catch (Exception e) {
            consumer.accept(e.getMessage());
        }
    }

进程流消费者:

public class ProcessStreamConsumer {
    private InputStream inputStream;
    private Consumer<String> consumer;

    public ProcessStreamConsumer(InputStream inputStream, Consumer<String> consumer) {
        this.inputStream = inputStream;
        this.consumer = consumer;
    }

    public void consumeStream() {
        new BufferedReader(new InputStreamReader(inputStream)).lines()
                .forEach(consumer);
    }
}

主类:

class Console{
  public final ConsoleReader console;
  public final BashExecutor bashExecutor;

  public Console() throws IOException {
    console = new ConsoleReader();
    console.setExpandEvents(false);
    bashExecutor = new BashExecutor();
  }

  public void println(Object in){
    try {
        console.println(in.toString());
        console.flush();
    } catch (Exception e) {
        e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    Console consoleMain = new Console();
    String input = consoleMain.console.readLine("grid>");
    while(true){
        if(input==null) input= "stop";

        input = input.trim();

        while(input.trim().equals("")){
            input = console.readLine(grid>);
        }

        if(input.startsWith("stop") || input.startsWith("qui")){
            System.exit(0);
        }
        if(input.startsWith("bash")) {
            bashExecutor.executeCommand(input, this::println);
            input=console.readLine("grid>");
            continue;
        }
  } 
}

我的想法是,我有一个使用 Jline 控制台库创建的控制台应用程序,它有一些我已经创建/将要创建的自定义命令。

但我希望能够在此控制台中执行 bash(交互模式),以便用户在想要执行某些 bash 命令时不必退出我的控制台应用程序。

使用我拥有的当前代码,它确实启动了 bash,并且我也能够执行 bash 命令,但我没有看到在 bash 提示符下键入的输入。

例如输出:

grid>bash
bash-4.2$ Mon Jun 15 02:57:14 EDT 2020
bash-4.2$ bash: wrongcommand: command not found
bash-4.2$ exit
grid>quit

如果您看到上面的 o/p,我看不到我输入的命令(日期、错误命令),但我可以执行它们并获取输出。

我也尝试使用带注释的代码,但它只是挂起并且屏幕本身上没有显示任何提示。

问题:

  1. 为什么我看不到在运行此命令的终端中输入的命令?
  2. 我也尝试使用 RedirectInput、RedirectOutput 作为 PIPE,但代码挂起,并且在运行 bash 命令后我无法在屏幕上看到任何内容
  3. 我应该怎样做才能让这项工作成功?
  4. 当我通过 processBuilder 运行 bash 命令时,我是否还可以加载 bashrc 文件作为配置文件,因为它有别名?

我检查了这个:Invoking bash from Java interactively

但我无法理解答案。仅当从终端调用 bash 时才会提示吗?

最佳答案

效果很好

ProcessBuilder processBuilder = new ProcessBuilder();
        try {
            processBuilder.command("stty", "echo");
            processBuilder.inheritIO();
            processBuilder.start().waitFor(1000, TimeUnit.MILLISECONDS);
            processBuilder.command("bash", "-i");
            processBuilder.redirectErrorStream(true);
            processBuilder.inheritIO();
            processBuilder.start().waitFor();
            processBuilder.command("stty", "-echo");
            processBuilder.inheritIO();
            processBuilder.start().waitFor(1000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            consumer.accept("exception occurred while starting bash");
            consumer.accept(e.getMessage());
        }

使用它我可以看到我正在输入的内容,但我不知道它为什么起作用。如果有人有更好的答案,请发布。

关于java - 如何使用 Java ProcessBuilder API 运行交互式 bash?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62383019/

相关文章:

java - 通过正则表达式验证连字符

node.js - 无法使用 n 更改 nodejs 版本

linux - 尾部格式化错误

linux - Bash读取txt文件并存储在数组中

bash - bash 中类似 zsh 的历史记录

linux - 仅当第二个文本文件中也存在时,才基于第一个文本文件中的第二个字段组合两个文本文件

java - 为高性能、安全、可扩展的 Web 应用程序选择正确的框架(前端、后端)

java - 如何在 selenium webdriver testng 中实现接口(interface)概念

java - 在java的构造函数中创建的未分配对象的生命周期是多少?

linux - jffs2 Linux 文件系统上的 O_DIRECT 支持