Get stdInput from a java Process before the process terminates - java

So I am trying to run a python script and want to obtain the stdInput from the script so I can use it. I have noticed the stdInput will hang until the process has finished.
Python script:
import time
counter = 1
while True:
print(f'{counter} hello')
counter += 1
time.sleep(1)
Java code:
public class Main {
public static void main(String[] args) throws IOException {
Runtime rt = Runtime.getRuntime();
String[] commands = {"python3", "/Users/nathanevans/Desktop/Education/Computing/Programming/Java/getting script output/src/python/main.py"};
Process proc = rt.exec(commands);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
System.out.println("stdOuput of the command");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("stdError of the command");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
}
Nothing is printed from the java application until the Process is terminated but in this case when I terminate the java application.
How would I obtain the stdInput as it is written by the script?

In order to get Python output immediately you'd need to turn off Python output buffering - that is covered here
This may fix your problem but you may run into second issue because you are reading STD IN / OUT in one thread. If STDERR buffer fills before you read to end of STDIN it will block the process. The solution then is to read STD/IN/ERR in separate threads or use ProcessBuilder which allows redirect to files or redirect STDERR to STDOUT:
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectOutput(outfile);
pb.redirectError(errfile);
//or
pb.redirectErrorStream(true);
Process p = pb.start();

Related

Not getting input data stream when execute another process from ProcessBuilder

I am new to java and i am calling a Python script from java using processbuilder and trying read python output in java.
ProcessBuilder pb = new ProcessBuilder(Arrays.asList("python","PyScript.py",""+path));
Process p = pb.start();
String line;
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = in.readLine()) != null)
{
System.out.println(line);
logger.debug("Value of python output is"+line);
System.out.println("in while loop");
}
readline is getting null. when i run through command prompt its running fine.

Opening cmd and waiting user input in cmd and exec commands from java

My problem is, after opening cmd from java code, i want user to be able to input like in c++ ms dos applications. When user writes sth such as "dir" or "cd..", i want to execute these codes by java.
The problem is for every command java re-opens cmd again. Also i cannot execute commands. My cmd start code is below ;
final ArrayList<String> commands = new ArrayList<>();
commands.add("cmd.exe");
commands.add("/C");
commands.add("start");
ProcessBuilder pb = new ProcessBuilder(commands);
Process process = pb.start();
Here's some cleaned up code from How to open the command prompt and insert commands using Java?
public static void main(String[] args) {
try {
String ss = null;
Runtime obj = null;
Process p = Runtime.getRuntime().exec("cmd.exe");
//write a command to the output stream
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
writer.write("dir");
writer.flush();
//Get the input and stderror
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("Here is the standard output of the command:\n");
while ((ss = stdInput.readLine()) != null) {
System.out.println(ss);
}
System.out.println("Here is the standard error of the command (if any):\n");
while ((ss = stdError.readLine()) != null) {
System.out.println(ss);
}
} catch (IOException e) {
System.out.println("FROM CATCH" + e.toString());
}
}

Java: is there a way to run a system command and print the output during execution?

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());
}

Running Python scripts in Java

I'm trying to run a python script during the execution of my java code, because it will depend on the output received from the python script. So far I've tried using jythonc, unfortunately to no success, and now im trying to use the java Runtime and java Process to execute the python script.
Now I've run into a problem when trying to call the python script. I feel as though it doesn't even call the script because it takes less than a couple seconds to get to the next page....
Could the problem be how I am calling the python script?? I am trying to run this through a web application...
Here is some of my code:
String run = "cmd /c python duplicatetestingoriginal.py" ;
boolean isCreated = fwr.writeFile(BugFile, GD, 500, true, 5, "LET");
if(isCreated){
try{
r = Runtime.getRuntime();
p = r.exec(run);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line = "";
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
}
while ((line = stdError.readLine()) != null) {
errorW.write(line);
}
int exitVal = p.waitFor();
arrayList = fwr.readResults();
}catch(Exception e){
}
}
else{
// troubleshoot....
}
Instead of String for the command, split it to chunks and make a String[]. No need to state cmd /c, I think.
This is a sample code from my application:
//Running on windows
command = new String[4];
command[0]=directory.getCanonicalPath()+"/data/ExtenalApp.exe"; //extenal commandline app, not placed in path, but in subfolder
command[1]=directory.getCanonicalPath()+"/data/SomeFile.txt"; //file needed for the external app, sent as an argument
command[2]=arg1; //argument for the app
command[3]=arg2; //argument for the app
//Running on Mac
command = new String[6];
command[0]="python";
command[1]=directory.getCanonicalPath()+"/data/wp.py"; //path to the script
command[2]="-F"; //argument/Flag/option
command[3]="--dir="+path; //argument/option
command[4]="--filename="+filename; //argument/option
command[5]=argument; //argument/option
Process process = Runtime.getRuntime().exec(command);
process.waitFor();
process.destroy();
I don't handle the Input/Output streams because the script/app doesn't require input, and outputs only when finished, nothing important. Which might not be the case for you.

Running Shell Script at the command line

I am running a Shell script using cygwin.
Process p;
InputStream in;
BufferedReader br;
String line;
String cmd;
cmd = "D:/cygwin/bin/bash -c '/bin/test/app.sh" +three_ltr_id+""+mon_code+""+year_code+""+part_no+""+version_no+" '";
System.out.println("EXECUTING: " + cmd);
p = Runtime.getRuntime().exec(cmd);
in = p.getInputStream();
p.waitFor();
br = new BufferedReader(new InputStreamReader(in));
System.out.println("OUT:");
while ((line = br.readLine()) != null) {
System.out.println(line);
System.out.println("SCRIPT EXECUTED PROPERLY");
This is showing EXECUTING and the commands that I passed to script.
If I go inside D:/cygwin/bin/test folder and run the same command it works.
When I run the same command at the command line it won't work.
You need to start reading the input from p.getInputStream() immediately, and keep reading it until there is no more. On Windows, there is little or no buffer in the pipe, and the process will hang once it is filled.
Same is true for the error stream. You could launch threads to read both streams, or there's an option in the way you launch processes to combine regular output and errors, and you can just read them from there.

Categories

Resources