I need to run command from my java application and process it's output.
The code is look like this:
public static void readAllOutput(){
try {
final String cmd = new String("find ~ -iname \"screen*\"");
System.out.println(cmd);
Process ps = Runtime.getRuntime().exec(cmd);
// ps.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(ps.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException /*| InterruptedException*/ e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I execute this command from OS I have a big output, but in my Java app the output is emty.
you need to use
getRuntime().exec( new String[] { "find", "~", "-iname","screen*"} );
or try
getRuntime().exec( new String[] { "find", "~", "-iname","\"screen*\""} );
inorder to accept arguments as double quotes.
Related
Im trying to run Yolo detector from a java GUI i wrote. I can start the detector using windows cmd like so:
cd <pathToYolo> \\ In my case named :C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64
darknet.exe detetctor test <pathToAConfigFile> <pathToAnotherConfigFile> <pathToModelDef> -dont_show <pathToImage>
I tried multiple aproaches. I used Runtime.getRuntime().exec() like so.
try {
String command = "darknet.exe detector test data\\obj.data cfg\\yolov4-obj.cfg backup\\rgbmodel\\yolov4-obj_last.weights -dont_show C:\\Users\\felix\\Desktop\\yoloTestSet\\RGBTest\\IMG_2392.jpg";
Process proc = Runtime.getRuntime().exec("cmd /c start /wait " + command, null,
new File("C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64"));
BufferedReader br = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
String line;
while ((line = br.readLine()) != null)
System.out.println(line);
proc.waitFor();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I also tried:
ProcessBuilder pb = new ProcessBuilder(
"cmd",
"/C",
"start",
"darknet.exe",
"detector",
"test",
"data\\obj.data",
"cfg\\yolov4-obj.cfg",
"backup\\rgbmodel\\yolov4-obj_last.weights",
"-dont_show",
"-ext_output",
"C:\\Users\\felix\\Desktop\\yoloTestSet\\RGBTest\\IMG_2392.jpg"
);
pb.directory(new File("C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64"));
try {
Process process = pb.start();
InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String output = null;
while ((output = bufferedReader.readLine()) != null) {
System.out.println(output);
}
//wait for the process to complete
//process.waitFor();
//close the resources
//bufferedReader.close();
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}
Both will run the process and print the desired output on cmd and closes the cmd afterwards. So far its just what i want. My problem now is, how can read this output properly.
br.readLine()
seems to be null.
If I leafe out the "start" before the actuall command, I can read the first line of the output, then everything gets stuck, leaving out "cmd" gives me this error:
Cannot run program "darknet.exe" (in directory "C:\AI\Yolo_v4\darknet\build\darknet\x64"): CreateProcess error=2, The system cannot find the file specified
The doku is a bit short on what the "cmd /C start" part actually does.
I would appreciate some advice on what is the issue here and how to do that properly,
regards Felix
Thanks to Daniel Junglas hint, I found this to be a solution.
try {
String command = "C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64\\darknet.exe detector test C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64\\data\\obj.data C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64\\cfg\\yolov4-obj.cfg C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64\\backup\\rgbmodel\\yolov4-obj_last.weights -dont_show -ext_output C:\\Users\\felix\\Desktop\\yoloTestSet\\RGBTest\\IMG_2392.jpg";
Process proc = Runtime.getRuntime().exec(command, null,
new File("C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64"));
BufferedReader br = new BufferedReader(
new InputStreamReader(proc.getErrorStream()));
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
String line;
while ((line = br.readLine()) != null)
System.out.println(line);
while ((line = stdInput.readLine()) != null)
System.out.println(line);
proc.waitFor();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Some of the desired output was inside the ErrorStream. Also you need full paths and do a minor change to YOLO itself, since there is an internal error raised. "cmd /c start" is not necassery.
The program is stuck at p2.waitFor() (I tested with printing strings before and after)
public void score() {
this.toXML();
try {
Process p = Runtime
.getRuntime()
.exec("python sumocfg_maker.py Carrefour.net.xml Detectors.det.xml edgedata.csv -ef");
p.waitFor();
Process p2 = Runtime.getRuntime().exec("python simulation.py");
new Thread(new Runnable() {
public void run() {
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
try {
while ((line = input.readLine()) != null)
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
p2.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
and simulation.py is
import os
os.system('cmd /c "sumo -c Simulation.sumocfg --duration-log.statistics --log duration.txt)
The simulation.py runs fine on its own. When I put the command in simulation.py in java, I get the same problem.
The System.out.println(line); prints out "Success" and then nothing
I left out code from simulation.py that saves a file that the java reads right after the p2.wait(), and without the p2.wait() the file never changes.
You have
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
But you need
BufferedReader input = new BufferedReader(new InputStreamReader(p2.getInputStream()));
since p is already finished, the bufferedreader will wait but never receive anything.
I am trying to use the apktool from a Java program. I'm using this for creating a web service. However this command does not run on the shell from the Java program.
String cmd = "apktool d /home/ridhima/Test.apk" ;
try {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while((line = reader.readLine()) != null)
{
System.out.print(line + "\n");
}
p.waitFor();
}
catch (IOException | InterruptedException e1) {
e1.printStackTrace();
}
The command works perfectly fine directly from the shell.
Thanks but it works fine now. Since apktool is a wrapper script, it is probably not being recognized through the java program. Extracting the apktool.jar directly works.
try {
ProcessBuilder pb = new ProcessBuilder("/home/ridhima/java/jdk1.8.0/bin/java", "-jar", "apktool.jar","d","test.apk");
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}
p.waitFor();
}catch (IOException | InterruptedException e1) {
e1.printStackTrace();
}
You maybe should wait for the process to complete
String cmd = "apktool d /home/ridhima/Test.apk" ;
try {
Process p = Runtime.getRuntime().exec(cmd);
// You maybe should wait for the process to complete
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while((line = reader.readLine()) != null)
{
System.out.print(line + "\n");
}
}
catch (IOException | InterruptedException e1) {
e1.printStackTrace();
}
Or you can use ProcessBuilder for the same task
public class Main {
public static void main(String[] args) throws java.io.IOException, java.lang.InterruptedException {
// Create ProcessBuilder instance for UNIX command ls -l
java.lang.ProcessBuilder processBuilder = new java.lang.ProcessBuilder("ls", "-l");
// Create an environment (shell variables)
java.util.Map env = processBuilder.environment();
env.clear();
env.put("COLUMNS", "3");
processBuilder.directory(new java.io.File("/Users"));
java.lang.Process p = processBuilder.start();
}
}
I have a shell script file called test.sh in the home directory ~. I want to execute the shell file using java. I use the following code:
Runtime runtime = Runtime.getRuntime();
Process process = null;
String cmd[] = {"/bin/bash","~/test.sh"};
String[] env = {"PATH=/bin:/usr/bin/"};
try
{
process = runtime.exec(cmd,env);
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line = reader.readLine();
stringBuilder.append(line);
System.out.println("The token is " + stringBuilder.toString() );
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
When I try to execute the following program, I get null as result like:
The token is null
where I'm making the mistake?
Edit:
test.sh has only
echo "Hello"
You need to read from the stream while the process is alive. It doesn't make sense to access getInputStream after waitFor() returns because the process had died by then. You should start a thread to read getInputStream().
Something like:
process = runtime.exec(cmd,env);
final BufferedReader reader = new BufferedReader(new InputStreamReader (process.getInputStream()));
final StringBuilder stringBuilder = new StringBuilder();
new Thread () {
public void run () {
String line = reader.readLine();
stringBuilder.append(line);
}
}.start ();
process.waitFor();
try {
String str;
Process process = Runtime.getRuntime().exec("bash /home/abhishek/workspace/Pro/run");
InputStream isout = process.getInputStream();
InputStreamReader isoutr = new InputStreamReader(isout);
BufferedReader brout = new BufferedReader(isoutr);
while ((str = brout.readLine()) != null) {
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
The Code has issues with getting the InputStream from the Process,
because if I run the Shell script from my Terminal it runs completely fine,
but if I Run the Script like this,the str is always null,
I am using this code to get the output of the Shell Script directly into Java instead writing the Script Output in the File
Is there any other way to achieve this,or how can I get the issue solved using the current approach
I think something returned through the error stream, so you can try to check something from the Process.getErrorStream().
You should also wait for the created process to prevent your main program completes before it. Use Process.waitFor();
public class TestMain {
private static final String BASH_CMD = "bash";
private static final String PROG = "/home/abhishek/workspace/Pro/run";
private static final String[] CMD_ARRAY = { BASH_CMD , PROG };
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String command = null;
try {
while ((command = reader.readLine()) != null) {
System.out.println("Command Received:" + command);
}
} catch (Exception ex) {
ex.printStackTrace();
// failed to listening command
}
}
}).start();
Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
process = processBuilder.start();
InputStream inputStream = process.getInputStream();
setUpStreamGobbler(inputStream, System.out);
InputStream errorStream = process.getErrorStream();
setUpStreamGobbler(errorStream, System.err);
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void setUpStreamGobbler(final InputStream is, final PrintStream ps) {
final InputStreamReader streamReader = new InputStreamReader(is);
new Thread(new Runnable() {
public void run() {
BufferedReader br = new BufferedReader(streamReader);
String line = null;
try {
while ((line = br.readLine()) != null) {
ps.println("process stream: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
Edit you /home/abhishek/workspace/Pro/run if it is a shell and add the following line on top.
#!/usr/bin/bash
and give required execute permissions to /home/abhishek/workspace/Pro/run.
Then use the following line
Process process = Runtime.getRuntime().exec("/home/abhishek/workspace/Pro/run");
Now if the run program prints anything you should see it in the output.
Your code looks fine. So, I believe that problem is either in command line you are using (bash /home/abhishek/workspace/Pro/run) or in your script itself.
I'd suggest you to perform the following steps:
try to run some well-known command instead of your script. For example pwd. Check that your code that is reading from input stream works correctly.
Now try to simplify your script. Create script run1 that just runs the same pwd. Now run this script from java and see that it is working. BTW you do not have to run it as bash yourscript. You can directly run it without bash prefix
If all this works start to move from simple to your real script step-by-step. I believe you will find your mistake. Probably your script cannot start for some environment related problems.
Possible problem is by the time you obtain inputStram the sub-process is not ready
Try
Process process = Runtime.getRuntime().exec("bash /home/abhishek/workspace/Pro/run");
InputStream isout = process.getInputStream();
process.waitFor()
Try something like this:
String[] runCommand = new String[3];
runCommand[0] = "sh";
runCommand[1] = "-c";
runCommand[2] = "bash /home/abhishek/workspace/Pro/run";
Process process = runtime.exec(runCommand);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine();
reader.close();
After multiple readings of the source code for the unix implementation of Process at https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.base/unix/classes/java/lang/ProcessImpl.java it seems that the standard redirects will always swallow to a ProcessBuilder.NullInputStream:
if (redirects[1] == Redirect.PIPE) {
std_fds[1] = -1;
}...
and
stdout = (fds[1] == -1 || forceNullOutputStream) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ProcessPipeInputStream(fds[1]);
(The same code repeats for stdIn, stdOut and stdErr streams)
The only workaround I have found, which feels very clumsy is to use a temp File:
File stdOutTmp; // create and destroy however you see fit
ProcessBuilder pb = ...;
pb.redirectOutput(ProcessBuilder.Redirect.to(stdOutTmp));
...
There are other static factory methods (Redirect.appendTo(File) to append to an existing file rather than overwrite an existing file, and Redirect.from(File) for stdIn)