I am running a java program in Windows that collects log from Windows events. A .csv file is created on which certain operations are to be performed.
The commands are execed and piped. How can I cause my Java program to wait until the process is finished?
Here is the code snippet I am using:
Runtime commandPrompt = Runtime.getRuntime();
try {
Process powershell = commandPrompt.exec("powershell -Command \"get-winevent -FilterHashTable #{ logname = 'Microsoft-Windows-PrintService/Operational';StartTime = '"+givenDate+" 12:00:01 AM'; EndTime = '"+beforeDay+" 23:59:59 '; ID = 307 ;} | ConvertTo-csv| Out-file "+ file +"\"");
//I have tried waitFor() here but that does not seem to work, required command is executed but is still blocked
} catch (IOException e) { }
// Remaining code should get executed only after above is completed.
You need to use waitFor() instead of wait(). That way your thread will block until the executed command finishes.
I found the answer here Run shell script from Java Synchronously
public static void executeScript(String script) {
try {
ProcessBuilder pb = new ProcessBuilder(script);
Process p = pb.start(); // Start the process.
p.waitFor(); // Wait for the process to finish.
System.out.println("Script executed successfully");
} catch (Exception e) {
e.printStackTrace();
}
}
This shall work. If not, specify WHAT exactly does not work
Runtime commandPrompt = Runtime.getRuntime();
try {
Process powershell = commandPrompt.exec("powershell -Command \"get-winevent -FilterHashTable #{ logname = 'Microsoft-Windows-PrintService/Operational';StartTime = '"+givenDate+" 12:00:01 AM'; EndTime = '"+beforeDay+" 23:59:59 '; ID = 307 ;} | ConvertTo-csv| Out-file "+ file +"\"");
powershell.waitFor();
} catch (IOException e) { }
// remaining code
Related
Using process builder in java but I want the program to wait while the process is finished.
I tried to use pb.wait() but it keeps on waiting. How do I wait till all the commands have finished executing?
This is a very small part of my code.
String[] commands = {All my commands go here};
String command = "cmd.exe /c " + String.join(" && ", commands);
ProcessBuilder pb = new ProcessBuilder(command.split(" "));
pb.inheritIO();
try {
pb.start();
try {
pb.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
System.out.println("Error, Could not run.");
e.printStackTrace();
}
}
The wait() method you called does not do what you expect (check javadoc for more details: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#wait(long))
You want to wait for the process you started:
Process p = pb.start();
p.waitFor();
see https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Process.html#waitFor()
I'm trying to run the command bash -i from a Java application, because I want the user be able to use the shell in middle of some work and then return to the Java application.
I have this test code:
import java.io.*;
public class exec {
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder b = new ProcessBuilder(args);
b.redirectError(ProcessBuilder.Redirect.INHERIT);
Process p = b.start();
InputStream pout = p.getInputStream();
PrintWriter pin = new PrintWriter(p.getOutputStream());
Thread in = new Thread(() -> {
while (true) {
try {
int i = System.in.read();
if (i == -1) break;
pin.write(i);
pin.flush();
} catch (IOException e) {
e.printStackTrace();
break;
}
}
System.err.println("in finished");
});
Thread out = new Thread(() -> {
while (true) {
try {
int i = pout.read();
if (i == -1) break;
System.out.write(i);
} catch (IOException e) {
e.printStackTrace();
break;
}
}
System.err.println("out finished");
});
out.start();
in.start();
p.waitFor();
}
}
After compiling, everything works well. I can even start the bash shell:
$ java exec date
ti 21.3.2017 19.03.25 +0200
out finished
^C$ java exec bash
date
ti 21.3.2017 19.03.30 +0200
^Cout finished
However, when I'm trying to start the bash -i shell, the terminal starts to behave strangely.
$ java exec bash -i
[1] + Stopped (tty input) java exec bash -i
$ user#computer:/tmp$ fg
java exec bash -i
date
date
ti 21.3.2017 19.05.21 +0200
user#computer:/tmp$ pwd
pwd
[1] + Stopped (tty input) java exec bash -i
The Java process is stopped, and the shell is sh again, I think. After writing fg the date command works one time, but the Java is again stopped when I try pwd.
Is there any way I can get this working? What I want is to have a normal interactive bash prompt started from a Java program.
It appears that the ProcessBuilder method inheritIO does what I want.
ProcessBuilder b = new ProcessBuilder(args);
b.inheritIO();
Process p = b.start();
I am trying to execute it via:
Process process = Runtime.getRuntime().exec(spark_cmd);
with no luck. The command ran via shell starts my application which succeeds. Running it via exec start a process which dies shortly after and does nothing.
When I try
process.waitFor();
it hangs and waits forever. Real magic begins when I try to read something from the process:
InputStreamReader isr = new InputStreamReader(process.getErrorStream());
BufferedReader br = new BufferedReader(isr);
To do so I start a thread that reads from the stream in a while loop:
class ReadingThread extends Thread {
BufferedReader reader;
Wontekk(BufferedReader reader) {
this.reader = reader;
}
#Override
public void run() {
String line;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Application starts, does some stuff, and hangs. When I abort my application, spark application wakes up (??????????) and completes remaining work. Does anyone have reasonable explanation of what is happening?
thanks
You can send spark job as spark-submit with the help of java code with the help of SparkLauncher so you can go though below link and check it our
https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/launcher/SparkLauncher.html
One way is Spark launcher as told by #Sandeep Purohit
I'd offer shell script approach with nohup command to submit job like this...
This worked for me incase of mapreduce executions... same way you can
try for spark background jobs as well.
Have a look https://en.wikipedia.org/wiki/Nohup
"nohup spark-submit <parameters> 2>&1 < /dev/null &"
When ever, you get messages then you can poll that event and call this shell script. Below is the code snippet to do this...
/**
* This method is to spark submit
* <pre> You can call spark-submit or mapreduce job on the fly like this.. by calling shell script... </pre>
* #param commandToExecute String
*/
public static Boolean executeCommand(final String commandToExecute) {
try {
final Runtime rt = Runtime.getRuntime();
// LOG.info("process command -- " + commandToExecute);
final String[] arr = { "/bin/sh", "-c", commandToExecute};
final Process proc = rt.exec(arr);
// LOG.info("process started ");
final int exitVal = proc.waitFor();
LOG.trace(" commandToExecute exited with code: " + exitVal);
proc.destroy();
} catch (final Exception e) {
LOG.error("Exception occurred while Launching process : " + e.getMessage());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
Moreover to debug
ps -aef | grep "your pid or process name"
Below command will list the open files opened by the process..
lsof -p <your process id >
Also, have a look at process.waitFor() never returns
I have the following method
public static void disableMobileDate()
{
try
{
Runtime rt = Runtime.getRuntime();
Process pr = null;
pr = rt.exec("C:\\Program Files\\Android\\android-sdk\\platform-tools\\adb shell svc data disable");
System.out.println("### Data disabled on mobile device! ###");
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Every time this method is ran from my program, it creates a adb.exe in task manager. The adb.exes (multiple adb.exe processes) stays there until I close my program. Is there anyway to make the process end after the command has been successfully executed?
You can call pr.destroy() after your command execution.
Or you can kill the process via the taskkill command:
rt.exec("taskkill /F /IM adb.exe")
You can kill the process by doing pr.destroy() to kill. But you should listen for the update that comes out, and once it prints what you are looking for, then you should kill it. A way to get the output is here.
I am writing a java app that needs to perform mysql dump, and I am using the runtime.exec, based in the when runtime.exec won't article. The code is below:
public int exectuteCommand(){
Runtime rt = Runtime.getRuntime();
logger.debug("exexuting cmd: " + showCommand());
int exit = -1;
try {
Process proc = rt.exec(cmd);
ExtProcessStreamHandler errorHandler = new ExtProcessStreamHandler(proc.getErrorStream(), "ERROR");
ExtProcessStreamHandler outHandler = new ExtProcessStreamHandler(proc.getInputStream(), "OUTPUT");
// kick it off
errorHandler.start();
outHandler.start();
exit = proc.waitFor();
} catch (IOException e) {
logger.error("ERROR!! ~~ executing command " + showCommand(), e);
e.printStackTrace();
} catch (InterruptedException e) {
logger.error("ERROR!! ~~ unexpected return for " + showCommand() + " , returned " + exit, e);
e.printStackTrace();
}
return exit;
}
1) The command that the process returns works in the shell (I'm running this on a mac). The first error I had was an inability to find the mysqldump command. That results in this error:
java.io.IOException: Cannot run program "mysqldump": error=2, No such file or directory
I resolved that by adding the complete path of the file to the command. The $PATH var shows
/usr/local/mysql/bin/mysqldump
as the complete path. How can I make sure my java app has that info?
2) when adding the complete path to the command, I get this error msg:
INFO [Thread-1] (ExtProcessStreamHandler.java:28) - external process ERROR : mysqldump: Couldn't find table: ">"
Here is the code that builds the command array:
return new String[] {MYSQLDUMP_CMD, "-u", USER_DEFAULT, "-p"+ PW_DEFAULT, TEST_DB_NAME,
">", DUMP_LOC};
again, when I copy the command passed to the java app into the shell on my mac, it works. Not sure what I'm doing wrong.
thanks in advance!
It thinks ">" is an argument intended for mysqldump. You are invoking an executable, not evaluating a shell expression. If you want to pipe your output, do it with the outHandler and errorHandler in your code.
An alternative is to invoke a shell and pass the expression you want to evaluate as an argument:
expr = new StringBuilder()
.append(MYSQLDUMP_CMD).append(' ')
.append("-u").append(USER_DEFAULT).append(' ')
.append("-p").append(PW_DEFAULT).append(' ')
.append(TEST_DB_NAME).append(' ')
.append(">").append(' ')
.append(DUMP_LOC)
.toString();
return new String[] {"/bin/bash", "-c", expr};
If your code to build the command array doesn't wrap spaced arguments in single quotes (or if the JDK doesn't do this for you), then modify the StringBuilder statement to create the wrapped quotes for you.
Below Code is worked for me
public static void backup() {
String currentDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy_MM_dd"));
String backupPath = String.format("%s/%s.%s", Helper.BACKUP_PATH, currentDate, "sql");
File backupFile = new File(backupPath);
if (!backupFile.exists()) {
try {
backupFile.createNewFile();
String mysqlCom=String.format("mysqldump -u%s -p%s %s",USER_NAME,PASSWORD,DB);
String[] command = new String[] { "/bin/bash", "-c",mysqlCom};
ProcessBuilder processBuilder = new ProcessBuilder(Arrays.asList(command));
processBuilder.redirectError(Redirect.INHERIT);
processBuilder.redirectOutput(Redirect.to(backupFile));
Process process = processBuilder.start();
process.waitFor();
LOGGER.info("Backup done");
} catch (IOException e1) {
e1.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
LOGGER.info("Database already backuped today");
}
}