In Java I want to execute a .lnk shortcut which it self executes a .exe file.
I run the executable like so:
String currentDir = new File(game.getGamePath()).getCanonicalPath();
ProcessBuilder processBuild = new ProcessBuilder(currentDir);
processBuild.command("cmd", "/c", "start" , currentDir);
Process = processBuild.start();
try {
Process.waitFor();
} catch (InterruptedException ex) {
Logger.getLogger(AuroraLauncher.class.getName()).log(Level.SEVERE, null, ex);
}
I want the waitFor() thread blocking method to wait until the actual executed application (.exe file) terminates before it continues not the shortcut. Is there a way to do this simply or do I have to somehow extract the .exe path from the .lnk? if so how would I do that?
"start" launches a separate process, so your process is done. But you can extract the actual executable path from the lnk file. take a look at this post.
Windows command "start" has an option /wait you must specify to tell him it has to wait for the end of the process.
This code run until you close notepad:
#Test
public void run() throws IOException {
String currentDir = new File(System.getProperty("user.home"),"desktop/notepad.lnk").getCanonicalPath();
ProcessBuilder processBuild = new ProcessBuilder(currentDir);
processBuild.command("cmd", "/c", "start","/wait", currentDir);
Process p= processBuild.start();
try {
p.waitFor();
} catch (InterruptedException ex) {
}
System.out.println("process terminated!");
}
Simpler than to parse the lnk file.
Your code certainly won't compile. You should fix it to compile and work as intended:
Process p = processBuild.start();
try {
p.waitFor(); // Ignoring the process result code.
} catch (InterruptedException ex) {
Logger.getLogger(AuroraLauncher.class.getName()).log(Level.SEVERE, null, ex);
}
Related
I am trying to run an async process and I do not want the program to wait until the end of these processes executions. I found this question how to run shell script asynchronously from within Java program but it doesn't have the answer that I am looking for.
What I am doing is I am simply running bash processes and after I run it, I do not want the Java program to wait until it's finished. This is what I have done:
public void runCommandLine(String directory) throws IOException {
Thread commandLineThread = new Thread(() -> {
try {
ProcessBuilder processBuilder = new ProcessBuilder(
"/bin/bash");
processBuilder.directory(new File(directory));
Process process = processBuilder.start();
try (OutputStreamWriter osw = new OutputStreamWriter(process.getOutputStream())) {
osw.write(command);
}
printStream(process.getErrorStream(), true);
printStream(process.getInputStream(), true);
} catch (IOException ex) {
ex.printStackTrace();
}
});
commandLineThread.start();
System.out.println("Task Dispatched");
}
I also put another print out at the end of the main method so I get this output:
Task Dispatched
Task Dispatched
End of psvm
However the program does not terminate as these two processes have not terminated.
How can I solve this issue?
You need to make your thread a daemon thread. Use setDaemon(true) before starting it.
commandLineThread.setDaemon(true);
A daemon thread is a thread that does not prevent the JVM from exiting. See this question: What is Daemon thread in Java? for more information about daemon threads.
Edit:
By judging from your comments you need the command to run even though the JVM is about to exit. I assume the command variable contains the script you want to run? You could make two changes to make the program behave as I think you want.
Start bash with -c to execute your command, then you do not have to send things to an output stream.
Start the process before starting your thread that waits for the output.
The resulting code would look something like:
public void runCommandLine(String directory) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(
"/bin/bash -c " + command);
processBuilder.directory(new File(directory));
Process process = processBuilder.start();
Thread commandLineThread = new Thread(() -> {
try {
printStream(process.getErrorStream(), true);
printStream(process.getInputStream(), true);
} catch (IOException ex) {
ex.printStackTrace();
}
});
commandLineThread.setDaemon(true);
commandLineThread.start();
System.out.println("Task Dispatched");
}
You are reading the output streams of your process, and thats the reason your java program does not exit:
printStream(process.getErrorStream(), true);
printStream(process.getInputStream(), true);
Your stream reading will keep blocking your code.
You may like to redirect output of your launched process to a log file and read that later.
Thread commandLineThread = new Thread(() -> {
try {
BufferedReader br=new BufferedReader(
new InputStreamReader(
process.getInputStream()));
String line;
while((line=br.readLine())!=null){
System.out.println(line);
}
} catch (IOException ex) {
ex.printStackTrace();
}
});
commandLineThread.setDaemon(true);
commandLineThread.start();
I am trying to run an async process and I do not want the program to wait until the end of these processes executions. I found this question how to run shell script asynchronously from within Java program but it doesn't have the answer that I am looking for.
What I am doing is I am simply running bash processes and after I run it, I do not want the Java program to wait until it's finished. This is what I have done:
public void runCommandLine(String directory) throws IOException {
Thread commandLineThread = new Thread(() -> {
try {
ProcessBuilder processBuilder = new ProcessBuilder(
"/bin/bash");
processBuilder.directory(new File(directory));
Process process = processBuilder.start();
try (OutputStreamWriter osw = new OutputStreamWriter(process.getOutputStream())) {
osw.write(command);
}
printStream(process.getErrorStream(), true);
printStream(process.getInputStream(), true);
} catch (IOException ex) {
ex.printStackTrace();
}
});
commandLineThread.start();
System.out.println("Task Dispatched");
}
I also put another print out at the end of the main method so I get this output:
Task Dispatched
Task Dispatched
End of psvm
However the program does not terminate as these two processes have not terminated.
How can I solve this issue?
You need to make your thread a daemon thread. Use setDaemon(true) before starting it.
commandLineThread.setDaemon(true);
A daemon thread is a thread that does not prevent the JVM from exiting. See this question: What is Daemon thread in Java? for more information about daemon threads.
Edit:
By judging from your comments you need the command to run even though the JVM is about to exit. I assume the command variable contains the script you want to run? You could make two changes to make the program behave as I think you want.
Start bash with -c to execute your command, then you do not have to send things to an output stream.
Start the process before starting your thread that waits for the output.
The resulting code would look something like:
public void runCommandLine(String directory) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(
"/bin/bash -c " + command);
processBuilder.directory(new File(directory));
Process process = processBuilder.start();
Thread commandLineThread = new Thread(() -> {
try {
printStream(process.getErrorStream(), true);
printStream(process.getInputStream(), true);
} catch (IOException ex) {
ex.printStackTrace();
}
});
commandLineThread.setDaemon(true);
commandLineThread.start();
System.out.println("Task Dispatched");
}
You are reading the output streams of your process, and thats the reason your java program does not exit:
printStream(process.getErrorStream(), true);
printStream(process.getInputStream(), true);
Your stream reading will keep blocking your code.
You may like to redirect output of your launched process to a log file and read that later.
Thread commandLineThread = new Thread(() -> {
try {
BufferedReader br=new BufferedReader(
new InputStreamReader(
process.getInputStream()));
String line;
while((line=br.readLine())!=null){
System.out.println(line);
}
} catch (IOException ex) {
ex.printStackTrace();
}
});
commandLineThread.setDaemon(true);
commandLineThread.start();
Is it possible to make java monitor if a cmd is done then runs another cmd?
For example...
btnStart.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent args)
{
try
{
String command = "cmd /c start "+DetectDrive+"\\starting.bat";
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException e1)
{
e1.printStackTrace();
}
if(checkbox.isSelected())
{
try
{
String command = "cmd /c start "+DetectDrive+"\\Stage1.bat";
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if(checkbox_1.isSelected())
{
try
{
String command = "cmd /c start "+DetectDrive+"\\Stage2.bat";
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
How do I make sure that once starting.bat finishing running in the cmd then if stage1 has been ticked then the stage1.bat will start running in the cmd???
And then after the stage1.bat finish running in the cmd, it will go backs to the code and check if stage2.bat is ticked, if it is, then stage2.bat will run.
Use Process.waitFor, but add /wait to your command to make then new process wait for the batch process to stop.
For example:
String command = "cmd /c start /wait Stage1.bat";
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
The new process creates a new batch process and then terminates without the /wait.
Use Process.waitFor(). It will wait until the command ends.
Process has a waitFor method
from the javadoc:
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
This method returns immediately if the subprocess has already terminated.
If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.
this is basically what I am trying to do: I created a Process that simulates the command line. Like this:
private Process getProcess() {
ProcessBuilder builder = new ProcessBuilder("C:/Windows/System32/cmd.exe");
Process p = null;
try {
p = builder.start();
} catch (IOException e1) {
e1.printStackTrace();
}
return p;
}
Now I can "feed" this process with commands:
BufferedWriter p_stdin = new BufferedWriter(
new OutputStreamWriter(process.getOutputStream()));
try {
p_stdin.write("dir"); // Just a sample command
p_stdin.newLine();
p_stdin.flush();
} catch (IOException e) {
e.printStackTrace();
return "Failed to run " + fileName;
}
What I now would like to do is wait for the command, that is the subprocess of my process, to complete. How can I do that? I know that I can wait for processes with the waitFor() method, but what about a subprocess??
The dir command is not a subprocess, it is executed internal to cmd. However, this is not much relevant, anyway: from the perspective of Java any other command, which is launched in a subprocess, would behave the same.
To wait for the dir command to complete you must interpret the incoming stdout output from cmd and realize when the prompt was printed again. This is a quite brittle mechanism, though.
In any case, you currently don't consume cmd's stdout at all, which will cause it to block soon, never recovering.
i ve written a simple program to run on a mac, the program opens an excel file and waits for the the user to close the file after which a simple output is given. when i run the program, excel opens, the proc.waitfor is ignored and it just skips to the output without waiting, any help
thanks
Thread myThread = new Thread() {
#Override
public void run() {
try {
String userDir = (System.getProperty("user.home"));
String fileName = userDir + "/Desktop/test/testfile.xlsx";
File theFile = new File(fileName);
Process proc = new ProcessBuilder("/usr/bin/open", fileName).start();
int waitFor = proc.waitFor();
} catch (InterruptedException ex) {
Logger.getLogger(MacTester.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MacTester.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
myThread.start();
System.out.println("excel is now closed");
This line:
System.out.println("excel is now closed");
Should be inside the run method. Your main thread, the thread that is starting your other thread continues with the execution after start has been invoked.
Another alternative is to place:
myThread.join();
on the line after:
myThread.start();
/usr/bin/open doesn't run modally, it returns the control after launching the appropriate application. You should use open -W. Consider using open -W -n which opens the file in a new instance of the application. Consult man open and try in terminal before testing your java code.
You're doing your process (appropriately) in a background thread, and so what effect will waitfor have on the completely separate calling thread? Answer: none. The solution I see has been given in the other answer -- +1 to him. :)