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.
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
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.
Related
In my program, I am running a command using Processbuilder.
The command is actually to execute python script. whatever the script printing, I am just showing it into the console by printing the input stream.
the problem is, inside the python script there is an if-condition the condition excepts Yes or No to continue the script.
I don't know how to give input Yes or No in-process builder.
Please help me to solve the problem.
The easiest way is using inheritIO().
With this option, you can use the java console as stdio for your python program. Your java program will run the python code and console used for both java and python program, so you can give input via java console.
ProcessBuilder test = new ProcessBuilder("python", PATH_OF_YOUR_PY_PROGRAM);
test.inheritIO();
Process process = test.start();
process.waitFor();
notice: inheritIO() uses the console for both input and output so by activating this option the whole python output will print in java console too.
The Java program has to launch few prorams that are launched using a command promt(one of them is nginx). How could I handle and send commands to the program from my Java application?
I found this library http://commons.apache.org/proper/commons-cli/usage.html But I'm not sure how it helps..
I do NOT need code. I need an explanation on how things like these work.
Well keep in mind its never a nice solution.
You act like you would be on a command line so you execute Commands like you would on the shell. And does always depend on your platform.
You said you don't want code, I will give it to you anyway ;)
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("service nginx start");
That is done with plan java.
I highly advise you to use a script language for that. Thats just not Java.
additional info:
One thing to remember is to use the streams on process to send input and check output (from Process class)
abstract InputStream getErrorStream()
Returns the input stream connected to the error output of the subprocess.
abstract InputStream getInputStream()
Returns the input stream connected to the normal output of the subprocess.
abstract OutputStream getOutputStream()
Returns the output stream connected to the normal input of the subprocess.
If you need to execute shell commands, this can be achieved like so (This example uses bash as the executing process)
Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","my_script.sh"});
You'll have to write your own script for this, but you don't even have to put it in a file. If you wanted to give user-like input to a command, keep in mind that you can pipe in the result of an echo to a command and it will act as a user typing that command. e.g
echo 1234 | pinTaker.sh;
This will effectively "type in" 1234 to the pinTaker script. This can also be used for things like typing in a password for ssh (Though this is not a good idea, it's a good example..)
I'm writing a shell script that's supposed to do the following.
- run a Java application that produces output
- run a shell command that produces output
- gather both outputs and send them out in an email
I have control of the source code of all the steps above.
Is there a best practice in gathering output from different sources? Should I redirect everything to a single temp file? Should I write different output to different files then concatenate them? What are the pros and cons of each approach?
If you don't worry about using just Java you could use the Runtime class to execute the shell command withing java (through exec) command, this will return you a Process object on which you have either getInputStream and getOutputStream so you will then be able to process the output of both the Java program and the shell command inside just one place and do whatever you want (keeping it in memory and directly send it by redirecting the outputstream to the inputstream of what you use to send the mail, with another exec) or saving it or whatever.
I'd favor using a second wrapper script which
calls the java program
calls the shell script
Captures output to a single file
reformats that output
suitable for mailing out Actually
does the mailing
Assuming you are using a unix shell, mailing/formatting and shell script calls are much simpler from the command line.
I'm working on a project in which I'd like to be able to turn lights on and off in the Duke Smart Home via a high frequency chirp. The lighting system is called Clipsal Square-D and the program that gives a user access to the lighting controls is called CGate. I was planning on doing some signal processing in Matlab, then create a batch file from Matlab to interact with Cgate. Cgate is a proprietary Java app that, if run from a DOS command line, opens up another window that physically looks like the DOS command prompt. I have a batch file that can check to see if Cgate is running and if not, open it.
But what I can't figure out how to do is actually run commands in the Cgate program from the batch file and likewise, take the response from Cgate. An example of such a command is "noop," which should return "200 OK."
Any help would be much appreciated! Thank you very much in advance :)
(here's my existing batch file by the way)
#ECHO off
goto checkIfOpen
:checkIfOpen
REM pv finds all open processes and puts it in result.txt
%SystemRoot%\pv\pv.exe
%SystemRoot%\pv\pv.exe > result.txt
REM if result has the word notepad in it then notepad is running
REM if not then it opens notepad
FIND "notepad.exe" result.txt
IF ERRORLEVEL 1 START %SystemRoot%\system32\Clipsal\C-Gate2\cgate.exe
goto end
:end
I don't know how to do this on Windows, but on UNIX, there is a program called expect that is designed for such a task. If you install Cygwin, you should be able to use the expect utility on Windows.
You're calling start cgate.exe, which will cause cgate.exe to be launched in a new window. First off, you probably want to run cgate in the same window, which means you should drop the start.
Secondly, you can use shell redirection to pass commands to the STDIN of cgate from a text file, like so:
cgate.exe < commands.txt
This will probably work, but it might not, depending on how cgate.exe is actually expected to receive its data.
If you want to have two-way communication, where you send in data, get the response, then send in more data depending on what the response was, you'll have to use something other than a batch file. Most scripting languages (perl, python) could be used for this purpose, or C or anything else.
I am trying to write tests that interact with GDB but am having trouble capturing the output. I would like for a log file to be generated which looks like what would have been seen in a terminal had the test been executed by hand. GDB is proving to be very stubborn when it comes to capturing its output however.
I've been able to write Expect scripts which are able to interact with GDB and whose output can be redirected to a log file but I don't want to write my tests in TCL. I'm hoping to use Groovy, which is compatible with Java. For some reason with Perl's Expect and ExpectJ the program output always goes to the terminal and can't be redirected to a file.
I tried starting a GDB process from Java using ProcessBuilder and it mostly works but the output of print statements never appear on stdout and can't be captured. I thought if Expect works then I'd launch expect from Java and have it interact with GDB but in this case most of the program output is lost, never appearing in the stdout of the created process.
So my question is, how can I write a test in Groovy (Java would be fine as well) which interacts with GDB and can capture all of the output?
Pseudo-code:
process = "gdb -q".execute()
waitForPrompt()
send("file exec")
waitForPrompt()
send("run")
send("quit")
Log file:
(gdb) file exec
Reading symbols from exec...done.
(gdb) run
Starting program: exec
<... output ...>
Program exited normally.
(gdb) quit
One possibility is that the GDB output is being dumped on standard error and you are only capturing standard output. You should be able to fix this with a redirect, something like this I think:
process = "gdb -q 2&>1".execute()
A second guess is that it may be worth checking what "show interactive-mode" says in the working and non-working cases. If they differ try "set interactive-mode off" before you do anything else.
A third option is to use GDB's logging facility to write the log file ("set logging file " and "set logging on") and avoid having to capture the output yourself.
If your test involves using gdb to actually debug something, as opposed to testing gdb itself, you should probably look into using the gdb/mi interface.