2

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.

slouc
  • 93
  • 1
  • 7

2 Answers2

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

Eric Renouf
  • 13,950
  • 3
  • 45
  • 67
  • Well yes, the prompt goes to `stderr`, but I think you've overlooked the most important part of those docs: "The prompt is displayed only if input is coming from a terminal." Input is *not* coming from a terminal in the situation the OP describes. – John Bollinger May 23 '15 at 01:10
  • @JohnBollinger true, though I was applying a little knowledge from an earlier question from this user where this was being invoked over an ssh session with `-t` so it should actually, in that case, think that it has a terminal. If that part of the situation has changed, then you're right that this won't help – Eric Renouf May 23 '15 at 01:19
  • Sorry for the confusion, here's the deal: invoking from Java with ssh -t works completely fine. I want to avoid the ssh -t part, but without it I get no output from bash. – slouc May 25 '15 at 07:18
  • I just realized that I can circumvent the awk part and still have problem with bash. I will edit my question now. – slouc May 25 '15 at 08:53
  • @slouc just updated my answer with a couple of things to try--though I don't know if they will really work in your case – Eric Renouf May 25 '15 at 12:15
  • I already tried the >/dev/tty trick but I get the message that no such thing exists (probably because I've got no active terminal for that process). I know I can probably get it to show up somehow by editing the bash script (e.g. by adding echo), but I cannot edit them (too long to explain, let's just say I can't). – slouc May 25 '15 at 15:15
  • Could you wrap the invocation in `screen` or `tmux`? I've not tried that either, but those would let you run the script inside a TTY, as far as it's concerned at least – Eric Renouf May 25 '15 at 15:18
1

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.

slouc
  • 93
  • 1
  • 7
  • Thank you for this link that helped me a lot too. I did not want to include the whole library so I just added the line `processBuilder.environment().put("TERM", "xterm");`, which make the `ProcessBuilder` act as if is was a terminal. – dounyy Aug 05 '15 at 15:35