I'm currently doing an Eclipse plugin mainly calling various scripts and interact with the return values.
my main problem is the ProcessBuilder. If I e.g. call a script that's creating a new Visual Basic window I'm not able to interact with the plugin anymore till I close the VB window. Seems that the cmd command is still running in the background and only after it stops the plugin responds again.
how am I able to fix it? should it run asynchronous in any way?
this is the ProcessBuilder I'm using:
public void execute(String scriptCMD) {
try {
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c",
scriptCMD);
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader r = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) {break;}
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
Here's a simple example of execution of the process asynchronously in another thread. I've used the single thread executor because there's only one task executed:
java.util.concurrent.Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c",
scriptCMD);
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader r = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) {break;}
System.out.println(line);
}
}
});
Related
I'm running my processes like this:
builder = new ProcessBuilder("/bin/bash", "-c", "./MessageGenerator | ./SimpleEchoServer");
process = builder.start();
Then process.destroy() or forciblyDestroy() doesn't work. Is it because I'm using a pipe? How can I kill these processes?
you should also split up the pipe command. I've written a little example:
package com.company;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder processBuilder;
String line;
processBuilder = new ProcessBuilder("/bin/bash", "-c", "ls -l", "|", "grep java");
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = reader.readLine()) != null) {
System.out.println ("Stdout: " + line);
}
Thread.sleep(10000);
process.destroy();
}
}
I have a problem with running ruby script in spring framework.
Let's say I have a script named 'my_script.rb', when I run it from terminal it works perfectly normal. When I execute it in "normal" java program:
public class RubyExecutor {
public static String execute(String command){
StringBuilder output = new StringBuilder();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
public static void main(String[] args){
System.out.println(RubtExecutor.execute("ruby /home/wookash/script.rb \"/home/wookash/rubyScripts\" \"case_0/\""));
}
script still works.
Problem comes when I put mentioned-above code in spring app.
What is weird: literally half of ruby script runs, magicly second half of lines of code is not being executed, no matter what is there. No errors, no warnings, nothing. I'm guessing that is caused by Spring task execution framework. However i have no idea how to fix it. Thank You in advance.
//EDIT I am pasting my spring method.
#RequestMapping("/execute")
public void executeCmd(){
executeCommand("ruby /home/wookash/script.rb \"/home/wookash/rubyScripts\" \"case_0/\"");
}
private String executeCommand(String command) {
StringBuilder output = new StringBuilder();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
I am able to print the output of an external program in Eclipse via the code below (found online, not mine). I would like to be able to pass a command to the program and THEN print the output of the program but I don't know how to pass commands to the program. Any suggestions would be appreciated, thanks!
Code:
String line;
Process p = Runtime.getRuntime().exec("Z:/LPCXpresso/test10/Debug/arm-none-eabi-readelf.exe");
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = bri.readLine()) != null) {
System.out.println(line);
}
bri.close();
while ((line = bre.readLine()) != null) {
System.out.println(line);
}
bre.close();
p.waitFor();
First I would recommend using ProcessBuilder instead of Runtime.getRuntime().exec(...)
Second to be able to interact with the different streams of the process started you need to do it concurrently, i.e. for each stream create an own Thread where you interact with it.
Here is a sample code wihch illustrates interaction with the command line prompt in windows cmd.exe
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("cmd.exe");
Process proc = pb.start();
// handle each of proc's streams in a separate thread
ExecutorService handlerThreadPool = Executors.newFixedThreadPool(3);
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to write to the stdin of the process
BufferedWriter stdin = new BufferedWriter(
new OutputStreamWriter(proc.getOutputStream()));
// read from our own stdin so we can write it to proc's stdin
BufferedReader myStdin =
new BufferedReader(new InputStreamReader(System.in));
String line = null;
try {
do {
line = myStdin.readLine();
stdin.write(String.format("%s%n", line));
stdin.flush();
} while(! "exit".equalsIgnoreCase(line));
} catch(IOException e) {
e.printStackTrace();
}
}
});
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to read the stdout of the process
BufferedReader stdout = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
String line;
try {
while(null != (line = stdout.readLine())) {
System.out.printf("[stdout] %s%n", line);
}
} catch(IOException e) {
e.printStackTrace();
}
}
});
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to read the stderr of the process
BufferedReader stderr = new BufferedReader(
new InputStreamReader(proc.getErrorStream()));
String line;
try {
while(null != (line = stderr.readLine())) {
System.err.printf("[stderr] %s%n", line);
}
} catch(IOException e) {
e.printStackTrace();
}
}
});
// wait for the process to terminate
int exitCode = proc.waitFor();
System.out.printf("Process terminated with exit code %d%n", exitCode);
handlerThreadPool.shutdown();
}
You could make it simple and redirect of the process stderr to stdout using ProcessBuilder#redirectErrorStream(true) before starting the process and then have only 2 threads, one for input and one for output
I know this question has been asked before but those answers didn't provide me an answer.
I want to execute a exec jar file in my java program and get the output from executing jar into a string. Here below are the codes I have used so far without success.
cmdlink = "java -jar iwtest-mac.jar"+" "+cmd;
System.out.println(cmdlink);
Process process = Runtime.getRuntime().exec(cmdlink);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {
st = reader.readLine();
}
process.waitFor();
and another code I have tried is as follows:
String cmdlink = "iwtest-mac.jar "+cmd;
ProcessBuilder pb = new ProcessBuilder("java", "-jar", cmdlink); //cmd here is a string that contains inline arguments for jar.
pb.redirectErrorStream(true);
pb.directory(new File("C:\\Users\\Dharma"));
System.out.println("Directory: " + pb.directory().getAbsolutePath());
Process p = pb.start();
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
for (String line = br.readLine(); line != null; line = br.readLine()) {
System.out.println( line );
p.waitFor();
Both of the above are not working for me. Any suggestions are appreciated.
This works For Me..
public class JarRunner {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "C:\\JCcc.jar");
pb.directory(new File("C:\\"));
try {
Process p = pb.start();
LogStreamReader lsr = new LogStreamReader(p.getInputStream());
Thread thread = new Thread(lsr, "LogStreamReader");
thread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class LogStreamReader implements Runnable {
private BufferedReader reader;
public LogStreamReader(InputStream is) {
this.reader = new BufferedReader(new InputStreamReader(is));
}
public void run() {
try {
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
This is what the Docs says-
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
You can pass any number of arguments in constructor.
Read more about process builder here.
I'm building a GUI with NetBeans, and one of the buttons in the GUI requires the use of a powershell script. I'm trying to get the script's output and put it into a JTextArea within the GUI. Here is what I have so far. I did a bit of debugging, and it seems to hang inside the while loop, but I'm confused as to why it's doing so.
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("cmd powershell C:/hello1.ps1");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
outputTextArea.setText(line);
}
reader.close();
proc.getOutputStream().close();
} catch (IOException ex) {
Logger.getLogger(BatchFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
And here is a simple powershell script I'm trying to get it to work with.
#Filename: hello1.ps1
Write-Host "Hello World!"
#End of Script
I did some researched, and I noticed that it was hanging for other people to, but only because they forgot to close the processes output stream.
I was having the same issue. I moved the proc.getOutputStream().close() before the while loop and everything worked
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
String allOutput = "";
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("cmd /c powershell C:/hello1.ps1");
BufferedReader errorReader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
BufferedReader outReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while ((line = errorReader.readLine()) != null) {
allOutput += "\n" + line;
}
while ((line = outReader.readLine()) != null) {
allOutput += "\n" + line;
}
int retVal = proc.waitFor();
} catch (IOException ex) {
Logger.getLogger(BatchFrame.class.getName()).log(Level.SEVERE, null, ex);
}
outputTextArea.setText(allOutput);
}
Form the command line properly with CMD.EXE /c
Check the ErrorStream
Use Process.waitFor() read the java-docs for the Process class.
No need to close the OutputStream since you never use it and the program shouldn't expect user input (java switching the names of input and output is annoying)
NOTE the code above isn't tested, so there may be syntax errors etc etc.
Here is my tested code, note the choice to "hack" or close STDIN when done.
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test
{
private static boolean hack=false;
public static void main(String[] args) throws IOException
{
Runtime rt = Runtime.getRuntime();
String cmd[];
if (hack)
cmd=new String[]{"cmd","/c","C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe","-File","c:\\cygwin\\home\\jpyeron\\test.ps1", "<NUL"};
else
cmd=new String[]{"C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe","-File","c:\\cygwin\\home\\jpyeron\\test.ps1"};
final Process p = rt.exec(cmd);
Thread stdout = new Thread()
{
public void run()
{
InputStream out = p.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(out));
String line = null;
try
{
while ((line = in.readLine()) != null)
{
System.out.println(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
};
};
stdout.start();
Thread stderr = new Thread()
{
public void run()
{
InputStream err = p.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(err));
String line = null;
try
{
while ((line = in.readLine()) != null)
{
System.out.println(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
};
};
stderr.start();
if (hack)
;
else
p.getOutputStream().close();
}
}
This helped me: Do not read the InputStream if there are no errors.
e.g.
private void takeAction () throws IOException, InterruptedException
{
String action = getAction (); // A powershell-Command
Process p = Runtime.getRuntime ().exec ( action );
InputStream is = p.getErrorStream ();
if ( 0 < is.available () )
{
BufferedReader br = new BufferedReader (
new InputStreamReader ( is ) );
String err = br.readLine ();
while ( null != err )
{
System.out.println ( "takeAction() " + err );
err = br.readLine ();
}
p.getOutputStream ().close ();
}
}