this class is response to execute the command ,the print the result
public class ExecutorTask implements Runnable{
#Override
public void run() {
Process process = null;
try {
process = Runtime.getRuntime().exec("cmd /c dir");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line="";
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
return;
}
}
}
the second class is a executor to run the shell use a thread
public final class ShellCommandExecutor{
public void execute(String command){
ExecutorTask task = new ExecutorTask();
Thread executorThread = new Thread(task);
executorThread.start();
/*try {
Thread.sleep(1000);
executorThread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
}
the problem is why i must in the class ShellCommandExecutor add code snippet:
try {
Thread.sleep(1000);
executorThread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
then can i see the print result:
2012-08-21 00:32 <DIR> .
2012-08-21 00:32 <DIR> ..
2012-08-21 00:32 1,576 .classpath
2012-08-21 00:26 1,224 .project
2012-08-07 10:58 <DIR> .settings
2012-08-24 15:19 10,965 pom.xml
2012-08-07 10:57 <DIR> src
2012-08-21 00:32 <DIR> target
2012-08-24 10:22 0 velocity.log
why?
You started a thread with
executorThread.start();
if you do nothing else the thread that started it (your main thread) will not wait for your executorThread to finish before returning, so your application will exit before this thread has executed its task.
To wait for your executorThread to finish you should call:
executorThread.join();
later in the code. At this point you will be ensured that it has finished its task.
Currently it works because you wait for 1 second in your main thread, during this second your other thread performs its action. But if your executorThread needed more than one second to perform it it will not work, so you should not sleep() in this case.
See Thread.join javadoc.
First of all why are you using String as a parameter in execute() method when you are not using it...
I tried your program with slight modification and it worked without sleep() and interrupt()
Try the code below.....
public final class ShellCommandExecutor{
public void execute(){
ExecutorTask task = new ExecutorTask();
Thread executorThread = new Thread(task);
executorThread.start();
/*try {
Thread.sleep(1000);
executorThread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
public static void main(String[] args){
new ShellCommandExecutor().execute();
}
}
class ExecutorTask implements Runnable{
#Override
public void run() {
Process process = null;
try {
process = Runtime.getRuntime().exec("cmd /c dir");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line="";
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
return;
}
}
}
Related
I'm using ProcessBuilder to launch an external process, but I need to be able to kill it. Right now I have no problem killing the process but for some reason the error stream doesn't close so the thread reading the stream never finishes. This keeps me from closing my program.
Here's where I start the threads reading from the input and error streams.
final Thread inputPrinter = new Thread() {
public void run() {
BufferedReader inputStream = new BufferedReader(new InputStreamReader(builder.getInputStream()));
String line;
try {
while ((line = inputStream.readLine()) != null) {
Util.println(line, false);
}
} catch (IOException e) {
} finally {
Util.println("input end");
try {
inputStream.close();
} catch (IOException e) {
}
}
}
};
inputPrinter.start();
Thread errorPrinter = new Thread() {
public void run() {
BufferedReader errorStream = new BufferedReader(new InputStreamReader(builder.getErrorStream()));
String line;
try {
while ((line = errorStream.readLine()) != null) {
Util.println(line, true);
}
} catch (IOException e) {
} finally {
Util.println("error end");
try {
errorStream.close();
} catch (IOException e) {
}
}
}
};
errorPrinter.start();
builder.waitFor();
Util.println("");
Util.println("Finished building project.");
Here's my code for stopping the process.
try {
builder.getOutputStream().close();
builder.getInputStream().close();
builder.getErrorStream().close();
} catch (IOException e) {
e.printStackTrace();
}
builder.destroy();
Util.println("");
Util.println("Build aborted by user.", true);
When I try to stop the process I get the following printed.
Build aborted by user.
Finished building project.
input end
I never get "error end" and debugging the program shows the thread is just sitting at "readLine()".
The code that waits for the process is running in it's own thread (separate from the code that kills the process).
What do I need to do to make sure that the errorPrinter thread dies?
I had the same problem,i use a speechRecognizer,so i am running a separate Thread which is running another .jar which prints to console and read the output using BufferedReader(something like this..):
//In seperate Thread from the Main App Thread
while (!stopped) {
while ((line = bufferedReader.readLine()) != null && !line.isEmpty()) {
System.out.println(line);
checkSpeechResult(line);
}
}
The problem
Basically the bufferedRead.readLine() lags until it has something to read.
If nothing comes it will wait forever.
Answer:
From another Thread call this:
process.destroy();
and it will stop the process so the bufferedRead.readLine() will exit.
Using unix OS, I am trying to run .sh file using ProcessBuilder in java Multi threading (.sh file is common, but arguments different for each thread). the code follows.
public class CLMScriptExe2 implements Runnable {
final String scriptFileName = "/apps/orangd1/temp/CLM/CLM_PCF_Jenkins.sh";
private String AppName;
public CLMScriptExe2(String appName) {
AppName = appName;
}
#Override
public void run() {
try {
ProcessBuilder processBuilder = new ProcessBuilder(scriptFileName, AppName);
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
//String line;
System.out.println(line);
}
try {
process.waitFor();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
System.out.println("ending executeScript--Testing");
}
public static void main(String[] args) {
CLMScriptExe2 c1 = new CLMScriptExe2("appOne");
Thread t1 = new Thread(c1);
t1.start();
CLMScriptExe2 c2 = new CLMScriptExe2("appTwo");
Thread t2 = new Thread(c2);
t2.start();
CLMScriptExe2 c3 = new CLMScriptExe2("appThree");
Thread t3 = new Thread(c3);
t2.start();
}
}
the Java program is terminating after processBuilder.start().
Edited:
after this processBuilder.start(), No logs, No errors, No Exception, nothing, it just terminated for all threads.
Is there any solution?
A bit late but maybe this will help someone else.
You are starting 3 threads but you aren't closing any ie you are missing:
t1.join();
etc
I suspect you are getting a ConcurrentModificationException error.
Recently I added "adb devices" in the nano ./bash_profile so that I can run it from any directory.
I used one java application to run
public static void main(String [] args) {
executeCmd("adb devices");
}
private static void executeCmd(String string) {
InputStream pipedOut = null;
try {
Process aProcess = Runtime.getRuntime().exec(string);
// These two thread shall stop by themself when the process end
Thread pipeThread = new Thread(new StreamGobber(aProcess.getInputStream()));
Thread errorThread = new Thread(new StreamGobber(aProcess.getErrorStream()));
pipeThread.start();
errorThread.start();
aProcess.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
class StreamGobber implements Runnable {
private InputStream Pipe;
public StreamGobber(InputStream pipe) {
if(pipe == null) {
throw new NullPointerException("bad pipe");
}
Pipe = pipe;
}
public void run() {
try {
byte buffer[] = new byte[2048];
int read = Pipe.read(buffer);
while(read >= 0) {
System.out.write(buffer, 0, read);
read = Pipe.read(buffer);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(Pipe != null) {
try {
Pipe.close();
} catch (IOException e) {
}
}
}
when I run any other commands such as "ls" it's working fine!!
I'm using mac ..
thanks :)
Maybe global path problem on mac. You can try run with absolute adb program path as command.
I want a java program to execute the following shell command:
apktool.jar d /path/to/my/app.apk
This command perfectly works when executing it directly on command line.
Java Code:
public static void main(String[] args) {
String command = "apktool d /path/to/my/app.apk";
try {
Runtime.getRuntime().exec(command);
} catch (IOException e1) {
e1.printStackTrace();
}
}
There is no error, no exception. Nothing happens and i have the impression that I already searched the entire internet for a solution. Does anybody know what I am doing wrong? A simple command like
mkdir /path/to/a/new/folder
works without problems.
I tried the same using ProcessBuilder:
try {
Process process = new ProcessBuilder(command).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This time i only get "Cannot run program "apktool d /path/to/my/app.apk, No such file or directory". I can't even run the mkdir command.
You need to call the jar with java.exe, and you're not doing that. Also you need to trap the input and error streams from the process, something you can't do the way you're running this. Use ProcessBuilder instead, get your streams and then run the process.
For example (and I can only do a Windows example),
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class ProcessEg {
private static Process p;
public static void main(String[] args) {
String[] commands = {"cmd", "/c", "dir"};
ProcessBuilder pBuilder = new ProcessBuilder(commands);
pBuilder.redirectErrorStream();
try {
p = pBuilder.start();
InputStream in = p.getInputStream();
final Scanner scanner = new Scanner(in);
new Thread(new Runnable() {
public void run() {
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
scanner.close();
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
try {
int result = p.waitFor();
p.destroy();
System.out.println("exit result: " + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Try doing it like this:
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec("./path/apktool d /path/to/my/app.apk");
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
system.out.println(output.toString());
Creating first a process allows you to wait for a response and reads the output of the execution of your process.
If something is failing while running your shell command, you will have the error printed at the end.
Also, make sure your java program can access your shell script, or better provide the full path to it like:
./path/to/shell/apktool d /path/to/my/app.apk
I want to launch a child proces and read its output until EOF or until an internal flag is cleared.
My first attempt was to call InputStream.close() in another thread, but although it works for sockets, it doesn't work with the result of Process.getInputStream(): the main thread is still waiting in read() and the killer thread either hangs in close0() (windows) or continues with no effect (linux).
Then I tried to check InputStream.available(), but it doesn't detect EOF: it returns 0.
public class BbbTest extends TestCase {
private Process proc;
private InputStream getStream() throws IOException {
//if ("".length() == 0) return new java.net.Socket("intra", 80).getInputStream();
String[] cmd;
if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
cmd = new String[] { "cmd", "/c", "more & more" };
} else {
cmd = new String[] { "sh", "-c", "cat; cat" };
}
Process proc = Runtime.getRuntime().exec(cmd);
return proc.getInputStream();
}
public void testB() throws Exception {
final InputStream in = getStream();
final Thread readingThread = Thread.currentThread();
Thread t = new Thread("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") {
#Override
public void run() {
try {
sleep(1000);
if (proc != null) proc.destroy(); // this won't help
readingThread.interrupt(); // this won't help either
in.close(); // this will do nothing and may even hang
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException ( );
}
}
};
t.setDaemon(true);
t.start();
try {
in.read();
assertTrue(false);
} catch (IOException e) {
// nothing
}
}
}
My last hope is to steal the channel from the returned stream and use nio
In windows , this Command will not terminate.
cmd = new String[] { "cmd", "/c", "more & more" };
Instead of try this simple command
cmd = new String[] { "cmd", "/c", "dir" };
And if you want to read your stream
public static void slurp(final InputStream is, final int bufferSize)
{
try(final Reader in = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(in);){
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Call this method by passing stream like this.
final BbbTest bbTest = new BbbTest();
Thread t = new Thread("xsdfds") {
#Override
public void run() {
try {
slurp(bbTest.getStream());
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException ( );
}
}
};
t.start();
If you want to kill the process from child thread.
Create setter and getter method for Process in BbbTest like this
public class BbbTest {
private Process proc;
/**
* #return the proc
*/
public Process getProc() {
return proc;
}
/**
* #param proc the proc to set
*/
public void setProc(Process proc) {
this.proc = proc;
}
private InputStream getStream() throws IOException {
String[] cmd;
if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
// cmd = new String[] { "cmd", "/c", "more & more" };
cmd = new String[] { "cmd", "/c", "dir" };
} else {
cmd = new String[] { "sh", "-c", "cat; cat" };
}
proc = Runtime.getRuntime().exec(cmd);
return proc.getInputStream();
}
}
Now using process you can destroy
bbTest.getProc().destroy();
If you want to kill the process based on output of other stream, you can add logic in slurp method by checking line content and terminate using destroy
UPDATE
Simple Demo
public class BbbTest {
private Process startProcess(String[] commands) throws IOException {
Process proc = Runtime.getRuntime().exec(commands);
return proc;
}
public static void slurp(final InputStream is)
{
try(final Reader in = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(in);){
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
if (line.equals("end")){
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) throws Exception {
final BbbTest bbTest = new BbbTest();
final Process process = bbTest.startProcess(new String[] { "cmd", "/c", "more" });
Thread t = new Thread("xsdfds") {
#Override
public void run() {
try {
slurp(process.getInputStream());
process.destroy();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException ( );
}
}
};
t.start();
try(OutputStream out = process.getOutputStream();
BufferedOutputStream outStream = new BufferedOutputStream(out);){
outStream.write("Test".getBytes());
outStream.write("\n".getBytes());
outStream.write("end".getBytes());
outStream.write("\n".getBytes());
outStream.flush();
}
}
}
Look at this sample : You should have some condition to terminate the child thread ( reading prcoess) like if the stream writes "end" / or End of EOF ( process closed inputstream )