2

I am writing a simple shell demo that highlights a problem I am having with JShell. When I pass JShell as an argument to /bin/zsh -c it works fine except for the fact that my Process echoes back whatever I send it.

Here is the code to my shell demo.

import java.io.*;

public class ShellDemo {

    private String[] cmd = new String[] {"/bin/zsh", "-c", "jshell"};
    private Process process;

    public ShellDemo() {}

    public void init() {
        try {
            ProcessBuilder pb = new ProcessBuilder(cmd);
            process = pb.start();
            read();
            listen();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }

    private void read() {
        Thread thread = new Thread(() -> {
            try (BufferedReader reader = process.inputReader()) {
                char[] buf = new char[10000];
                while (reader.ready() || process.isAlive()) {
                    int count = reader.read(buf, 0, 10000);
                    System.out.print(new String(buf, 0, count));
                }      
                int exitVal = process.waitFor();
                System.out.println("Process exited with value " + exitVal + "\n");
            } catch (IOException | InterruptedException ex) {
                System.err.println(ex);
            }
        });
        thread.start();
    }

    private void listen() {
        Thread thread = new Thread(() -> {
            try (
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                BufferedWriter writer = process.outputWriter();
            ) {
                while (process.isAlive()) {
                    String line = reader.readLine();
                    writer.write(line);
                    writer.newLine();
                    writer.flush();
                }
            } catch (IOException ex) {
                System.err.println(ex);
            }
        });
        thread.start();
    }

    public static void main(String[] args) {
        ShellDemo demo = new ShellDemo();
        demo.init();
    }
}

Then I compile and run my shell demo, and you'll see the echo in the output.

% javac ShellDemo.java
% java ShellDemo      
|  Welcome to JShell -- Version 17.0.1
|  For an introduction type: /help intro

jshell> System.out.println("hello world");
System.out.println("hello world")hello world

jshell> 

See how System.out.println("hello world") gets echoed before the "hello world" message is read by the inputReader? Why does zsh or JShell echo what I send it?

Is there a way to avoid the echo? What's the best solution?

ktm5124
  • 11,861
  • 21
  • 74
  • 119
  • remember that stdin, stdout and stderr need appropriate bindings to do what you need. – Mike 'Pomax' Kamermans Feb 12 '22 at 02:05
  • @Mike'Pomax'Kamermans System.in and System.out are streams and you can read directly from System.in and write directly to System.out. The idea behind the bindings is that they facilitate character reading and character writing and buffering data to improve performance – ktm5124 Feb 12 '22 at 05:59

0 Answers0