I am messing with Runtime.getRuntime(), but I don't think it really what I want.
I want something that has both user input, and output that goes to stdout. I would like a whole seperate program to get launched, basically.
Grae
Doing this:
Process process = Runtime.exec( "somecommand.exeorwhatever" );
Will run a completely separate process. Then you can use:
InputStream in = process.getInputStream();
InputStream err = process.getErrorStream();
OutputStream out= process.getOutputStream();
You can use Process created with ProcessBuilder.start() method and use its input and output streams.
Here is simple example:
public static void main(String[] args) throws Exception {
String[] processArgs = new String[]{"ping","google.com"};
Process process = new ProcessBuilder(processArgs).start();
BufferedReader in = new BufferedReader(new InputStreamReader(
//I'am using Win7 with PL encoding in console -> "CP852"
process.getInputStream(), "CP852"));
String line;
while ((line = in.readLine()) != null)
System.out.println(line);
in.close();
System.out.println("process ended");
}
Related
(I'm using Windows 7) I know how to start a process, pass some arguments and read the output of that process.
import java.io.*;
class Test {
public static void main(String args[]) throws IOException {
ProcessBuilder pb
= new ProcessBuilder("java", "ProgramFoo", "ArgBar");
Process process = pb.start();
final InputStream is = process.getInputStream();
BufferedReader reader
= new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
But what I want to do, is to read the output of a running process. Maybe by its PID or name.
Any Ideas?
Check out http://commons.apache.org/proper/commons-exec/ for better handling of processes.
Alternatively, you could get an InputStream from the process you already have and read it like this:
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuffer stringBuffer = new StringBuffer();
stdout = br.readLine();
while (stdout != null) {
stringBuffer.append(stdout);
stdout = br.readLine();
}
I am writing a javacode to call a interactive shellscript and using process builder for calling shellscript. I know that to pass parameters to this shell script i have to take its inputstream to check it's output and need to use output stream to pass command to it. My question is that how would I know using Input Stream that it's prompting for entering values ?
My code :
ProcessBuilder pb2=new ProcessBuilder("/home/abhijeet/sample1.sh","--ip="+formobj.getUpFile().getFileName(),"--seqs="+seqs);
script_exec = pb2.start();
OutputStream in = script_exec.getOutputStream();
InputStreamReader rd=new InputStreamReader(script_exec.getInputStream());
pb2.redirectError();
BufferedReader reader1 =new BufferedReader(new InputStreamReader(script_exec.getInputStream()));
StringBuffer out=new StringBuffer();
String output_line = "";
while ((output_line = reader1.readLine())!= null)
{
out=out.append(output_line+"/n");
System.out.println("val of output_line"+output_line);
//---> i need code here to check that whether script is prompting for taking input ,so i can pass it values using output stream
}
Is there any way to know directly that script is waiting for an input from user?
Read the process output stream and check for the input prompt, if you know the input prompt, then put the values to process inupt stream.
Otherwise you have no way to check.
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
BufferedReader b1 = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter w1 = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
String line = "";
String outp = "";
while ((line = b1.readLine()) != null) {
if (line.equals("PLEASE INPUT THE VALUE:")) {
// output to stream
w1.write("42");
}
outp += line + "\n";
}
...
UPD: for your code it should be something like that
ProcessBuilder pb2=new ProcessBuilder("/home/ahijeet/sample1.sh","--ip="+formobj.getUpFile().getFileName(),"--seqs="+seqs);
script_exec = pb2.start();
OutputStream in = script_exec.getOutputStream();
InputStreamReader rd=new InputStreamReader(script_exec.getInputStream());
pb2.redirectError();
BufferedReader reader1 =new BufferedReader(new InputStreamReader(script_exec.getInputStream()));
StringBuffer out=new StringBuffer();
String output_line = "";
while ((output_line = reader1.readLine())!= null)
{
out=out.append(output_line+"/n");
System.out.println("val of output_line"+output_line);
//---> i need code here to check that whether script is prompting for taking input ,so i can pass it values using output stream
if (output_line.equals("PLEASE INPUT THE VALUE:")) {
// output to stream
in.write("42");
}
}
I have a python script and it takes a long time to finish. I would like to run it from Java, but also output the script's output while it is executing, so that I can tell if it is properly running.
I've searched and only found examples where we output the output after the system command has finished, rather than during its execution.
Any way to do it while the script is running?
Here's what I have
public void doSomething() throws IOException {
String[] callAndArgs = {"python", "/hi.py"};
Process p = Runtime.getRuntime().exec(callAndArgs);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
i managed to get it working like this (Note it requires java7):
package test;
import java.lang.ProcessBuilder.Redirect;
public class Test {
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("python","/home/foobar/Programming/test/src/test/test.py");
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
p.waitFor();
}
}
python (note i flush on python to make it work using sys.stdout.flush())
import time,sys
c =0
while c<=50:
time.sleep(1)
print("----")
c = c +1
sys.stdout.flush()
Note if you don't want to flush in a loop you can use this:
ProcessBuilder pb = new ProcessBuilder("python","-u","/home/foobar/Programming/NetBeansProjects/test/src/test/test.py");
Redirect.INHERIT
Indicates that subprocess I/O source or destination will be the same as those of the current process. This is the normal behavior of most operating system command interpreters (shells).
I've searched and only found examples where we output the output after
the system command has finished, rather than during its execution.
That's weird, because your example should be dumping the output as the command is executing.
Instead of using BufferedReader, you could try reading directly from the InputStream instead as the required conditions for readLine might not be being met until after the process exits.
I'd also recommend that you use a ProcessBuilder over Process directly, as, apart from anything else, it allows you to redirect the output from the error stream into the input stream, allowing you to read just one stream instead of two...
This might also be an issue with Python and how it flushes it output buffers...
For example, rather then waiting for the BufferedReader to decide when to return, try printing each character from the stream as it occurs/is reported
ProcessBuilder pb = new ProcessBuilder("test.py");
pb.redirectError();
Process p = pb.start();
InputStream is = null;
try {
is = p.getInputStream();
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char)in);
}
} finally {
try {
is.close();
} catch (Exception e) {
}
}
Update
Doing a little reading, Python seems to be buffering its out out before sending it to the stdout. I don't think you can fix this on the a Java side, but need to alter either the way Python is run or the script works.
See How to flush output of Python print? for more details
I'm suspecting that you are writing to stderr, which you can't see because you are blocking on stdin. Use a ProcessBuilder instead of doing exec. This way, you can redirect stderr and stdin into a single stream.
Here is an example:
import java.io.*;
public class Test {
public static void main(String... args) throws IOException {
ProcessBuilder pb =
new ProcessBuilder("test.py");
pb.redirectErrorStream(true);
Process proc = pb.start();
Reader reader = new InputStreamReader(proc.getInputStream());
BufferedReader bf = new BufferedReader(reader);
String s;
while ((s = bf.readLine()) != null) {
System.out.println(s);
}
}
}
Alternatively you can spawn threads to read from stdin/stderr respectively.
Another thing to look for is output buffering by python. You can see if this is the cause by doing:
import sys
sys.stdout.flush()
after you write to stdout
Don't use #readLine as the conditional in your while loop. Instead wrap your inputStream in a scanner and use #hasNextLine()
Scanner in = new Scanner(p.getInputStream());
while (in.hasNextLine()) {
System.out.println(in.nextLine());
}
Lets say, that i have launched simple Java application, that outputs some strings to standart console using following command:
Runtime.getRuntime().exec("Path:/to/app.exe");
What i need is to gather all data, that launched app throws to the console. Is it possible? Thanks.
Paul.
You can use ProcessBuilder and get its IutputStream. Here is simple example:
public static void main(String[] args) throws Exception {
String[] processArgs = new String[]{"ping","google.com"};
Process process = new ProcessBuilder(processArgs).start();
BufferedReader in = new BufferedReader(new InputStreamReader(
//I'am using Win7 with PL encoding in console -> "CP852"
process.getInputStream(), "CP852"));
String line;
while ((line = in.readLine()) != null)
System.out.println(line);
in.close();
System.out.println("process ended");
}
I have a Shell Scripts that read the Input
#!/bin/bash
echo "Type the year that you want to check (4 digits), followed by [ENTER]:"
read year
echo $year
I'm executing this shell scripts using JAVA APi
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "/junk/leaptest.sh");
final Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
System.out.println("Program terminated!");
In the Java Console I can see the Output
Type the year that you want to check (4 digits), followed by [ENTER]:
Now the Actual Problem in How to pass the values to the Shell Scripts in my scripts how the varialble "year" can be read
I have edited the code as per the suggestion but doesn't work where we correct it
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "/junk/leaptest.sh");
final Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
/*
* OutputStream os = process.getOutputStream(); PrintWriter pw = new
* PrintWriter(os);
*/
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
while ((line = br.readLine()) != null) {
System.out.println(line);
// pw.println("8999");
bw.write("2012");
}
System.out.println("Program terminated!");
You can use the OutputStream of the Process class:
OutputStream os = process.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.println("1997");
What you write to this output stream will become the input stream of the shell script. So read year will read 1987 to the year variable.
EDIT:
I also tried it out and I've managed to find the problem. The 1997 string hasn't reached the script, beacuse PrintWriter buffers the data that was written to it. You either have to flush the PrintWriter stream after the println() with pw.flush() or you have to set the auto-flush property to true upon creation:
PrintWriter pw = new PrintWriter(os, true);
Here is the complete code that was working fine for me:
leaptest.sh:
#!/bin/bash
echo "Type the year that you want to check (4 digits), followed by [ENTER]:"
read year
echo $year
Test.java:
import java.io.*;
class Test {
public static void main(String[] args) {
try {
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "leaptest.sh");
final Process process = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
PrintWriter pw = new PrintWriter(process.getOutputStream());
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
pw.println("1997");
pw.flush();
}
System.out.println("Program terminated!");
} catch(Exception e) {
e.printStackTrace();
}
}
}
Output:
$ java Test
Type the year that you want to check (4 digits), followed by [ENTER]:
1997
Program terminated!
To pass values from java program that executes script to the script use command line arguments. If you want to send information back from script to java program print the value in script, read the script's STDOUT in java program and parse it.
You really almost there. Now you are reading the script output (into while loop) but you are just printing it. Parse the output and do what you need with it.
Think you should parse input stream is to extract your values. Parse it by lines.
You want to set up an OutputStream using getOutputStream aswell, to be able to write data from your Java program into the process.
public abstract OutputStream getOutputStream()
Gets the output stream of the subprocess. Output to the stream is piped into the standard input stream of the process represented by
this Process object.
I think this should work. You need to handle your subprocess' output stream. Read the docs.
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
bw.write("2012");