Search code examples
javalinuxshelltty

Why can't I start `bash -i` using ProcessBuilder in Java?


I'm trying to run the command bash -i from a Java application, because I want the user be able to use the shell in middle of some work and then return to the Java application.

I have this test code:

import java.io.*;
public class exec {
        public static void main(String[] args) throws IOException, InterruptedException {
                ProcessBuilder b = new ProcessBuilder(args);
                b.redirectError(ProcessBuilder.Redirect.INHERIT);
                Process p = b.start();
                InputStream pout = p.getInputStream();
                PrintWriter pin = new PrintWriter(p.getOutputStream());
                Thread in = new Thread(() -> {
                        while (true) {
                                try {
                                        int i = System.in.read();
                                        if (i == -1) break;
                                        pin.write(i);
                                        pin.flush();
                                } catch (IOException e) {
                                        e.printStackTrace();
                                        break;
                                }
                        }
                        System.err.println("in finished");
                });
                Thread out = new Thread(() -> {
                        while (true) {
                                try {
                                        int i = pout.read();
                                        if (i == -1) break;
                                        System.out.write(i);
                                } catch (IOException e) {
                                        e.printStackTrace();
                                        break;
                                }
                        }
                        System.err.println("out finished");
                });
                out.start();
                in.start();
                p.waitFor();
        }
}

After compiling, everything works well. I can even start the bash shell:

$ java exec date
ti 21.3.2017 19.03.25 +0200
out finished
^C$ java exec bash
date
ti 21.3.2017 19.03.30 +0200
^Cout finished

However, when I'm trying to start the bash -i shell, the terminal starts to behave strangely.

$ java exec bash -i
[1] + Stopped (tty input)        java exec bash -i
$ user@computer:/tmp$ fg
java exec bash -i
date   
date
ti 21.3.2017 19.05.21 +0200
user@computer:/tmp$ pwd  
pwd
[1] + Stopped (tty input)        java exec bash -i

The Java process is stopped, and the shell is sh again, I think. After writing fg the date command works one time, but the Java is again stopped when I try pwd.

Is there any way I can get this working? What I want is to have a normal interactive bash prompt started from a Java program.


Solution

  • It appears that the ProcessBuilder method inheritIO does what I want.

    ProcessBuilder b = new ProcessBuilder(args);
    b.inheritIO();
    Process p = b.start();