Invoking bash from Java interactively

2019-08-03 16:37发布

问题:

I have a Java application which invokes (using Runtime.getRuntime().exec) a bash script like this:

read -e -p "Are you sure you want to do this? (y/n)? "
echo "$REPLY"

The problem is, I never get the prompt part from the bash script (the "Are you sure..." text).

Is there a way to invoke an interactive bash script from Java so that I can read its output? I need it in order to be able to determine which question I'm being asked by the script (in reality it's a much bigger script than described here).

If I run the process from Java through SSH channel with the -t flag (accent on the t flag, without that it won't work), it works fine. But I would like to avoid having to ssh to myself in order to run the script properly, or more precisely, to read its output properly.

回答1:

From the bash man page when talking about read:

-p prompt
    Display prompt on standard error, without a trailing new‐
    line, before attempting to read any input.  The prompt is
    displayed only if input is coming from a terminal.

So you should make sure you are also capturing stderr if you want to see that message. You can perhaps do this when invoking it from java by adding 2>&1 but I'm not positive that java's invocation will honor that.

If you're using ProcessBuilder to invoke it, you should add a call to redirectErrorStream(true) on the process to get stderr visible via stdout reading.

I have not tried to verify this myself, but this page suggests redirecting stdout for the process to /dev/tty to make it think it's connected directly to the tty for the java process. So you'd add a &>/dev/tty to redirect stdout and stderr to /dev/tty, and hopefully that will get it to show up--though that may have it show up on stderr of the controlling Java process instead of the subprocess. I'm not too sure about that.

If you can't do that, another thing to consider would be to try to modify the script so it does an echo -n "<msg>"; read REPLY so the prompt will be displayed on stdout by echo instead of not at all by read



回答2:

OK, here' the deal.

As Eric pointed out, prompt is displayed only if input is coming from a terminal, so I needed a pseudo terminal to fool the bash script. I managed to do it by using JPty library.