Java exec stdin没有刷新

时间:2016-02-25 02:36:13

标签: java bash unix

对于学校项目,我正在尝试用Java创建一个终端。终端按以下方式工作:

  1. 用户键入命令
  2. 编程抓取命令并用字符串

    中的命令替换<command>
    /bin/bash -c "cd current/directory/; <command>; echo kjsfdjkadhlga; pwd
    
  3. 程序启动通过ProcessBuilder对象

  4. 创建的流程
  5. 程序产生一个从stdout和stderr
  6. 读取的线程
  7. 程序继续查找用户输入,如果命令运行完毕,则用户输入的内容将作为命令运行,否则将作为输入提供给当前运行的命令。
  8. 当生成输出时,程序查看kjsfdjkadhlga字符串的输出,以便它知道用户的命令何时完成运行,然后抓取剩余的输出并将其存储为当前路径用户在。
  9. 这是如何工作/一切的原因:

    为了避免自己不得不实现我自己的输入解析器来处理线路上的多个命令,IO重定向以及与ProcessBuilder一起使用的东西,我只是将命令转换为bash脚本让bash执行它。

    由于每个进程只执行一个命令(或者在创建时给出的任何命令,在这种情况下是单个用户命令)然后终止,所以不存储特定于进程的信息,例如当前工作目录。要传输该信息,我在用户命令之后调用pwd,然后在下一个命令的过程中,但在运行用户命令之前,我cd到该目录,有效地允许$PWD的值在进程之间保持不变。

    问题:

    除了需要用户交互时,一切正常。如果用户只是键入cat,它应该等待一行用户输入,然后打印,然后等待一行用户输入,然后打印,并永远重复(我不要处理 Crtl + C 然而......)。然而,实际发生的是终端等待一行用户输入,然后打印它,然后终止而不等待更多输入。

    我尝试过:

    目前,我为正在运行的命令提供输入:

     BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
     stdin.write(input);
     stdin.newLine();
     stdin.close();
    

    如果不是调用close(),而是调用flush(),那么cat会等待用户输入并且在我终止终端程序之前没有做任何事情,此时它会打印用户输入的所有内容。

    似乎flush()功能实际上并没有做任何事情。使用原始OutputStream并调用write()而不是使用BufferedWriter时提到的堆栈溢出问题。但是,这具有相同的效果。在OutputStream的{​​{1}}文档中,它指出&#34; flush()的flush方法不执行任何操作。&#34;

    我也尝试使用OutputStream,但文档说它的BufferedOutputStream函数只是强制将缓冲的数据写入基础flush,而不是OutputStream改变OutputStream没有刷新流的事实。

    This问题似乎是最有希望的问题,但在实施时我无法解决问题。这可能是因为我使用的是Mac OS而不是Windows。

    如果保持stdin打开足够长的时间以提交多行输入,或者如果我说错了,有人知道怎么做吗?

    代码

    main()的

    Terminal terminal = new Terminal();
    Scanner in = new Scanner(System.in);
    
    while (in.hasNextLine())
    {
        String line = in.nextLine();
        terminal.sendInput(line, terminal);
    }
    

    由main

    调用的terminal.sendInput()
    // ProcessReaderDelegate implements functions called when receiving output on stdout, stderr, and when the process terminates.
    public int sendInput(String text, ProcessReaderDelegate delegate)
    {
        if (processes.size() > 0)
        {
            processes.get(0).sendInput(text);  // Is a ProcessReader object
            return 1;
        }
    
        run(text, delegate);   // runs the given text as the <command> text described above
        return 2;
    }
    

    由terminal.sendInput()

    调用的ProcessReader的sendInput()
    public boolean sendInput(String input)
    {
        try
        {
            // stdin and process are a instance fields
            // tried this and doesn't seem to work (with either flush or close)
            stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
            stdin.write(input);
            stdin.newLine();
            stdin.close();
    
            // tried this and doesn't seem to work (with either flush or close)
            //BufferedOutputStream os = new BufferedOutputStream(process.getOutputStream());
            //os.write(input.getBytes());
            //os.write("\n".getBytes());
            //os.flush();
            //os.close();
    
            return true;
        }
        catch (IOException e)
        {
            System.out.println("ERROR: this should never happen: " + e.getMessage());
            return false;
        }
    }
    

    terminal.run()由terminal.sendInput()

    调用
    public void run(String command, ProcessReaderDelegate delegate)
    {
        // don't do anything with empty command since it screws up the command concatentaion later
        if (command.equals(""))
        {
            delegate.receivedOutput(null, prompt);
            return;
        }
    
        try
        {
            // create the command
            List<String> list = new ArrayList<String>();
            list.add(shellPath);
            list.add(UNIX_BASED ? "-c" : "Command : ");
    
            String cmd = (UNIX_BASED ? getUnixCommand(command) : getWindowsCommand(command));
            list.add(cmd);
            //System.out.println("command='" + list.get(0) + " " + list.get(1) + " " + list.get(2) + "'");
    
            // create the process and run it
            ProcessBuilder builder = new ProcessBuilder(list);
            Process p = builder.start();
            ProcessReader stdout = new ProcessReader(p, delegate, this);
            new Thread(stdout).start();
    
            processes.add(stdout);
        }
        catch (IOException e)
        {
            System.out.println(e.getMessage());
        }
    }
    

    ProcessReader.run()在线程中执行并读取stdout和stderr

    public void run()
    {
        try
        {
            boolean hitend = false;
            String buffer = "";
    
            while (true)
            {
                int c;
                String text;
    
                // ======================================================
                // read from stdout
                // read the next character
                c = stdout.read();
    
                // build the string
                while (c != -1)     // while data available in the stream
                {
                    buffer += (char)c;
                    c = stdout.read();
                }
    
                // send the string to the delegate
                if ((!hitend) && (buffer.length() > 0))
                {
                    // END_STRING is the "kjsfdjkadhlga" echoed after the command executes
                    int index = buffer.indexOf(END_STRING);
    
                    if (index >= 0)
                    {
                        hitend = true;
                        text = buffer.substring(0, index);
                        buffer = buffer.substring(index + END_STRING.length());
    
                        if (outputDelegate != null)
                        {
                            outputDelegate.receivedOutput(process, text);
                        }
                    }
                    else
                    {
                        for (int i = END_STRING.length() - 1; i >= 0; i--)
                        {
                            index = buffer.indexOf(END_STRING.substring(0, i));
    
                            if (i == 0)
                            {
                                index = buffer.length();
                            }
    
                            if (index >= 0)
                            {
                                text = buffer.substring(0, index);
                                buffer = buffer.substring(index + i);
    
                                if (outputDelegate != null)
                                {
                                    outputDelegate.receivedOutput(process, text);
                                }
                            }
                        }
                    }
                }
    
                // ======================================================
                // read from stderr
                // read the next character
                c = stderr.read();
                text = "";      // slow method; make faster with array
    
                // build the string
                while (c != -1)     // while data available in the stream
                {
                    text += (char)c;
                    c = stderr.read();
                }
    
                // send the string to the delegate
                if ((text.length() > 0) && (outputDelegate != null))
                {
                    outputDelegate.receivedError(process, text);
                }
    
                // ======================================================
                // check if the process is done (and hence no more output)
                boolean done = false;
    
                try
                {
                    int value = process.exitValue();
                    done = true;        // if got to this point, then process is done
    
                    // read the ending environment variables
                    Map<String, String> env = new HashMap<String, String>();
                    String[] words = buffer.split(" ");
    
                    env.put(ENV_WORKING_DIR, words[0]);
    
                    if (envDelegate != null)
                    {
                        envDelegate.processTerminatedWithEnvironment(process, env);
                    }
    
                    // end the process
                    outputDelegate.processEnded(process);
                    stdout.close();
                    stderr.close();
    
                    break;
                }
                catch (Exception e) {System.out.println(e.getMessage());}   // no exit value --> process not done
    
                if (done)   // just on the off chance that closing the streams crashes everything
                {
                    break;
                }
            }
        }
        catch (IOException e)
        {
            System.out.println("ERROR: ProcessReader: " + e.getMessage());
        }
    }
    

0 个答案:

没有答案