is it possible to send a command to an running Process like in the example below?
And how would you do that?
Process p = pb.start();
Most possibly not what you are wanting to achieve, but yes, you can communicate to a running Process with Process.getOutputStream()
For processes that read and write to the command line use p.getOutputStream() to send data to the process and p.getIntputStream() to read data from the process. For GUI processes you need native code to send messages depending on the operating system.
Edit:
Example code for processes that are reading/writing to the console:
Process process = pb.start();
// process stdout
Scanner stdout = new Scanner(
new BufferedReader(
new InputStreamReader(process.getOutputStream())));
// process stdin
PrintWriter stdin = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(process.getInputStream())), true);
// sending commands to the process
stdin.println("command1");
stdin.println("command2");
stdin.println("command3");
// reading process output
while (stdout.hasNextLine()) {
System.out.println("Process output: " + stdout.nextLine());
}
Related
I call a external Python script as Java process and want to send data to this. I create a process and try to send a string. Later the python script should wait for a new input from Java, work with this data and wait again(while true loop).
Python Code (test.py):
input = input("")
print("Data: " + input)
Java Code:
Process p = Runtime.getRuntime().exec("py ./scripts/test.py");
BufferedWriter out = new BufferedWriter(new
OutputStreamWriter(p.getOutputStream()));
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
System.out.println("Output:");
String s = null;
out.write("testdata");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
The process and output of simple prints works, but not with input and BufferedWriter.
Is it possible to send data to this python input with a Java process?
I read from other solutions:
create a Python listener and send messages to this script
import the external script to Jython and pass data
Are this better solutions to handle my problem?
use Process class in java
what is process class ?
this class is used to start a .exe or any script using java
How it can help you
Create your python script to accept command line variables and send your data from java class to python script.
for Example:
System.out.println("Creating Process");
ProcessBuilder builder = new ProcessBuilder("my.py");
Process pro = builder.start();
// wait 10 seconds
System.out.println("Waiting");
Thread.sleep(10000);
// kill the process
pro.destroy();
System.out.println("Process destroyed");
Later the python script should wait for a new input from Java
If this has to happen while the python process is still a subprocess of the Java process, then you will have to use redirection of I/O using ProcessBuilder.redirect*( Redirect.INHERIT ) or ProcessBuilder.inheritIO(). Like this:
Process p = new ProcessBuilder().command( "python.exe", "./scripts/test.py" )
.inheritIO().start();
If the python process is going to be separate (which is not the case here, I think) then you will have to use some mechanism to communicate between them like client/server or shared file, etc.
I am new to this console problems. I am simply creating a application which executes few command lines. I have a commands
mysql -u root -p
which is for opening MySQL console.
Here, how can I input password?
I did:-
cd c:\\Program Files (x86)\\MySQL\\MySQL Server 5.5\\bin
&& mysql -u root -p && root && create database testingdb;
&& quit && mysql –u root –p testingdb < mysql_dump.testingdb.sql
Here, first input is root which is password and second mysql_dump.testingdb.sql is sql file located in mysql_dump package.
This is not working and a thread is opened even though cmd console window is close.
How does java work in this situation?
Running the command
ProcessBuilder provides a full API for starting commands.
ProcessBuilder processBuilder = new ProcessBuilder("mysql", "-u", "root", "-p");
processBuilder.directory(new File("myDir"));
pb.redirectErrorStream(true);
Process proc = pb.start();
Pipe into the command
You can write strings into a BufferedWriter that wraps the confusingly named "output" stream from the Process object returned by processBuilder.start()
OutputStream stdin = proc.getOutputStream();
OutputStreamWriter osr = new OutputStreamWriter(stdin);
BuffererWriter bw = new BuffererWriter(osr);
bw.write("Hello\n");
A word of warning
You need to be very careful when using Process to consume the standard output/error streams otherwise the process can lock. A robust implementation should create 2 threads to read stdout and stderr asynchronously and perhaps a 3rd to feed the process.
The parent process uses these streams (#getInputStream(),
getErrorStream()) to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer
size for standard input and output streams, failure to promptly write
the input stream or read the output stream of the subprocess may cause
the subprocess to block, and even deadlock.
This guide When Runtime.exec() won't has all the information you need.
you can use Runtime class to execute OS commands. Since i donot have mysql installed canot check the senario mentioned. checked with cmd commands.
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("mysql -u root -p");
InputStream is = pr.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String inputLine;
while ((inputLine = in.readLine()) != null){
System.out.println(inputLine);
}
I want to run PianoBar from a Java GUI (PianoBar is a program that runs Pandora from command line). I thought this would be quick and dirty, but I guess I don't know enough about interaction between programs.
I use ProcessBuilder to launch an instance of PianoBar like so:
private Process createPianoBarProcess() throws IOException {
String[] command = {"CMD", "/C", "pianobar"};
ProcessBuilder probuilder = new ProcessBuilder( command );
probuilder.redirectErrorStream(true);
probuilder.directory(new File("~~location where pianobar.exe is~~"));
Process process = probuilder.start();
return process;
}
After I create the process, I create a BufferedReader to read in the PianoBar output:
Process pianoBar = createPianoBarProcess();
InputStream inS = pianoBar.getInputStream();
InputStreamReader isr = new InputStreamReader(inS);
BufferedReader br = new BufferedReader(isr);
But when I read the output from PianoBar via this reader, it spits out the first line of PianoBar ("Welcome to pianobar (2013.05.19-win32)! Press ? for a list of commands."), then it spits out the next line ("[?] Email:"). Then it just hangs.
Obviously, it is waiting for the user to input their email. But no matter what I try, I can't get my Java program to write the email to the PianoBar process when prompted - it just hangs as soon as it reads out the last character.
Is it possible to do what I am trying to do? I thought it would be an easy thing to look for on the internet, but I haven't been able to find anything. All I want is an easy way to write to the external process when prompted. Seems like this should be easy...
You may use the following code snippet to get working:
String s;
//s = email
BufferedWriter bufferedwriter = new BufferedWriter(new OutputStreamWriter(pianoBar.getOutputStream()));
bufferedwriter.write(s);
bufferedwriter.flush();
Done!
Remember to surround the code block with appropriate try/catch
I know to use ErrorStream or OutputStream you do the following
Process process = Runtime.getRuntime ().exec ("the command you want to execute");
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
What if I don't want to start a new process, I want to get the ErrorStream & OutputStream of the current application I am working on. (The current process).
How to get it ?
You use System.out and System.err.
Everything works fine on the command line, but when I translate what I want into Java, the receiving process never gets anything on stdin.
Here's what I have:
private void deployWarFile(File warFile, String instanceId) throws IOException, InterruptedException {
Runtime runtime = Runtime.getRuntime();
// FIXME(nyap): Use Jsch.
Process deployWarFile = runtime.exec(new String[]{
"ssh",
"gateway",
"/path/to/count-the-bytes"});
OutputStream deployWarFileStdin = deployWarFile.getOutputStream();
InputStream deployWarFileStdout = new BufferedInputStream(deployWarFile.getInputStream());
InputStream warFileInputStream = new FileInputStream(warFile);
IOUtils.copy(warFileInputStream, deployWarFileStdin);
IOUtils.copy(deployWarFileStdout, System.out);
warFileInputStream.close();
deployWarFileStdout.close();
deployWarFileStdin.close();
int status = deployWarFile.waitFor();
System.out.println("************ Deployed with status " + status + " file handles. ************");
}
The script 'count-the-bytes' is simply:
#!/bin/bash
echo "************ counting stdin bytes ************"
wc -c
echo "************ counted stdin bytes ************"
The output indicates that the function hangs at the 'wc -c' line -- it never gets to the 'counted stdin bytes' line.
What's going on? Would using Jsch help?
You might try closing the output stream before you expect wc -c to return.
IOUtils.copy(warFileInputStream, deployWarFileStdin);
deployWarFileStdin.close();
IOUtils.copy(deployWarFileStdout, System.out);
warFileInputStream.close();
deployWarFileStdout.close();
Would using Jsch help?
Using JSch would only help if you would be using the setInputStream() and setOutputStream() methods of the channel instead of the IOUtils.copy method, since they manage the copying on a separate thread.
ChannelExec deployWarFile = (ChannelExec)session.openChannel("exec");
deployWarFile.setCommand("/path/to/count-the-bytes");
deployWarFile.setOutputStream(System.out);
deployWarFile.setInputStream(new BufferedInputStream(new FileInputStream(warFile)));
deployWarFile.connect();
(Here you somehow have to wait until the other side closes the channel.)
If you simply replaced the Runtime.exec with opening an ChannelExec (and starting it after getting the streams), the problem would be completely the same, and could be solved by the same solution mentioned by antlersoft, i.e. closing the input before reading the output:
ChannelExec deployWarFile = (ChannelExec)session.openChannel("exec");
deployWarFile.setCommand("/path/to/count-the-bytes");
OutputStream deployWarFileStdin = deployWarFile.getOutputStream();
InputStream deployWarFileStdout = new BufferedInputStream(deployWarFile.getInputStream());
InputStream warFileInputStream = new FileInputStream(warFile);
deployWarFile.connect();
IOUtils.copy(warFileInputStream, deployWarFileStdin);
deployWarFileStdin.close();
warFileInputStream.close();
IOUtils.copy(deployWarFileStdout, System.out);
deployWarFileStdout.close();
(Of course, if you have longer output, you will want to do input and output in parallel, or simply use the first method.)
You probably get an error, but the process hangs because you are not reading the error stream.
Taken from the Process JavaDoc
All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (Process.getOutputStream(), Process.getInputStream(), Process.getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
So you need to read all of them. Using the ProcessBuilder is probably easier