I am new to process building and I am trying to get a java program that will call another java program that expects inputs before printing. After looking through stackoverflow it seems I need a processbuilder for each command and for each process. I am unsure if the flowing process will be interacting with the java program launched? Currently the program doesn't throw any errors but I am not getting the final print. I have provided both programs.
import java.util.Scanner;
public class test {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
sc.nextLine();
sc.nextLine();
System.out.println("you have done it");
}
}
public class test2 {
public static void main(String args[]){
Process process;
ProcessBuilder pb = new ProcessBuilder("java -jar Test.jar");
try {
process = pb.start();
process.waitFor();
ProcessBuilder pb1 = new ProcessBuilder("no");
Process process1 = pb1.start();
process1.waitFor();
ProcessBuilder pb2 = new ProcessBuilder("no");
Process process2;
process2 = pb2.start();
process2.waitFor();
System.out.println(process2.getInputStream());
}catch(Exception e){
}
}
}
I want to execute Bash commands from within a Java program running on a Windows desktop. I installed Cygwin, and I have found the following code:
public class BashRunner {
private static final Logger log = Logger.getLogger(BashRunner.class.getName());
public static void run(String comand) throws IOException, InterruptedException {
Runtime run = Runtime.getRuntime();
String[] env = new String[] {"path=%PATH%;C:/cygwin/bin/"};
Process proc = run.exec(new String[]{"bash.exe", comand}, env);
proc.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while (br.ready()) {
System.out.println(br.readLine());
}
}
}
The problem is that the process enters an infinite loop...
The BashRunner.run(String) method is called from the main method of my program like so:
BashRunner.run("ls -alt");
I am trying to run a command from Java that will start a process that runs for several minutes. I need to just trigger the command and get the process handle and continue with other operations in a loop. At regular intervals, I will have to monitor that the process is still active.
I also need the console window to display to show the output of the process for the user.
Currently, I have tried methods from both Runtime and ProcessBuilder classes to run my command but neither of them has helped me achieve my objective.
Sample code:
//Changing the directory and running Maven exec: java command on the POM file in that directory.
String cmd = "cd C:/Test & mvn exec:java";
String finalCmd = "cmd /c \""+ cmd +"\"";
Process process = Runtime.getRuntime().exec(finalCmd);
Thread.sleep(10);
boolean alive = process.isAlive();
The value of variable alive is True, but I don't see the process got started. When the program execution is complete, only then the process starts and I am not sure why that happens.
Also to display the console window, I found from google that I need to use the below command:
String finalCmd = "cmd /c start cmd.exe /c \"" + cmd + "\"";
However, with this, the process starts immediately but I do not get the process handle as I find the alive variable shows false.
Does someone know how this objective can be achieved? I am ok if it's not possible to do both at the same time but at least I need to get the process execution to start and get the handle to monitor the process state later in my code.
Couple of things that are happening incorrectly here:
We need to pass our command as string tokens to the exec() command
We need to wait for the process to exit with process.waitFor() instead of sleeping, this will block the current thread so if you don't want that you need to execute this in another thread or use an ExecutorService.
Advisable to check the output value of waitFor() to see if our command executed properly (value of 0) or not (any other value,
typically a positive 1 in case of unsuccessful execution)
Optionally (to see the output) we need to redirect the standard OUT and ERR somewhere, say print it to console(), though you could put it to a file some GUI window etc.
So at a minimum the following code should work:
Process process = Runtime.getRuntime().exec(new String[] {"cmd", "/c", "cd", "C:\\dev", "&&", "dir"});
int outputVal = process.waitFor();
boolean alive = process.isAlive();
System.out.format("alive %s, outputVal: %d\n",alive, outputVal);
Further suggestions:
use ProcessBuilder instead of runTime.exec(), it allows more control
and is the recommended way since JDK 1.5
read the inputStream
So the code will look some thing like this:
List<String> cmdList = Arrays.asList("cmd", "/c", "cd", "C:\\dev", "&&", "dir");
ProcessBuilder pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true); //redirect STD ERR to STD OUT
Process process = pb.start();
try (final BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line = null;
while ((line = br.readLine()) != null) {
System.out.println("std-out-line: " + line);
}
}
int outputVal = process.waitFor();
System.out.format("outputVal: %d\n", outputVal);
Since waitFor() is a blocking call, you can execute this in a separate thread or using an executorService. Sample code here:
final StringBuffer outputSb = new StringBuffer();
ExecutorService executorService = null;
try {
executorService = Executors.newSingleThreadExecutor();
final Future<Integer> future = executorService.submit(new Callable<Integer>() {
#Override
public Integer call() throws Exception {
try (final BufferedReader br = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line = null;
while ((line = br.readLine()) != null) {
outputSb.append("std-out-line: ");
outputSb.append(line);
outputSb.append('\n');
}
}
int exitValue = process.waitFor();
System.out.format("exitValue: %d\n", exitValue);
return exitValue;
}
});
while (!future.isDone()) {
System.out.println("Waiting for command to finish doing something else..");
Thread.sleep(1 * 1000);
}
int exitValue = future.get();
System.out.println("Output: " + outputSb);
} finally {
executorService.shutdown();
}
Here's a solution that uses WMIC.
public static void main( String[] args ) throws Exception {
// Vars
Process process;
String output;
// Execution
process = Runtime.getRuntime().exec("cmd /c wmic process call create calc.exe | findstr ProcessId");
output = readTrimmedOutput(process.getInputStream());
System.out.println("Output from command: " + output);
// Basic string manipulation to get process id
String str_proc_id = output.split(" = ")[1].replace(";","");
System.out.println("ProcessId is: " + str_proc_id);
// Some thread delay that you can comment/uncomment for testing if running or not
Thread.sleep(5000);
// Finding if process is still running
process = Runtime.getRuntime().exec("cmd /c wmic process get processid | findstr " + str_proc_id);
output = readTrimmedOutput(process.getInputStream());
boolean isRunning = output.contains(str_proc_id);
System.out.println("Is process still running? " + isRunning);
}
private static String readTrimmedOutput(InputStream is) throws Exception {
BufferedReader breader = new BufferedReader(new InputStreamReader(is));
String line = breader.readLine();
return line != null ? line.trim() : "";
}
Sample output
Output from command: ProcessId = 6480;
ProcessId is: 6480
Is process still running? true
For showing/displaying cmd console change some lines to:
// Execution
String your_command = "cmd.exe /c \"dir\"";
process = Runtime.getRuntime().exec("cmd /c wmic process call create \"" + your_command + "\" | findstr ProcessId");
References:
https://msdn.microsoft.com/en-us/library/aa394531(v=vs.85).aspx
https://www.computerhope.com/wmic.htm
since I didn't quite understand what you really need,i brought a comprehensive example of openning cmd from a java class (for instance class A) and starting a process of another java class (class B) and doing some operation from class B while class B is informing class A of whether it is processing yet or not. so the whole thing is to excecute class B from command promt that class A started and sending information from class B to A to notify it that it's still running.
in my example i took Main class as class A and myProcess class as class B.
as you can see in code below the Main class is Opening cmd and is executing myProcess class then myProcess class is sending a information about the process through the socket that was created in Main class
//imports
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
//class
public class Main
{
//fields
//methods
public static void main(String[] args) throws Exception
{
Runtime run = Runtime.getRuntime();
String new_dir = "C:\\Users\\Parsa\\Desktop\\New folder (2)";//imagine the directory of myProcess.class is in this folder
startServer();
run.exec("cmd.exe /c cd \""+new_dir+"\" & start cmd.exe /k \"java myProcess\"");
}
public static void startServer()
{
Thread myThread = new Thread()
{
#Override
public void run()
{
ServerSocket ss;// creating an open port for receiving data from network
try {
ss = new ServerSocket(60010);//open port number 60010--> it can really be anything that is empty
Socket s = ss.accept();//Listens for a connection to be made to this socket and accepts it
BufferedReader in = new BufferedReader(
new InputStreamReader(s.getInputStream()));//get the inputstream and change it to a buffered reader in order to get a string from remote network
String line = null;
while ((line = in.readLine()) != null) //read the input
{
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
myThread.start();
}
}
myProcess class:
by the way you need to compile the myProcess class manually by command prompt and excecute myProcess.class file from Main class
and the myProcess class is
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;
public class myProcess extends Thread
{
//field
//methods
public static void main(String[] args) throws Exception
{
System.out.println("myProcess has started");
startSender();
}
public static void startSender()
{
Thread myThread = new Thread()
{
#Override
public void run()
{
try
{
Socket s = new Socket("localhost", 60010);
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
for(int i = 0 ; i<10 ; i++)
{
out.write("Process in running");
out.newLine();
out.flush();
Thread.sleep(200);
}
out.close();
//do whatever here
System.out.println("myProcess output");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
myThread.start();
if(!myThread.isAlive())
{
System.out.println("myProcess has finished");
}
}
}
since i didn't exactly understand what you wanted ,this is probably not exactly what you want, but... it will definitely help you if you manipulate the code.
I believe that you need to launch you application as the process and not the CMD and then launch a child process of the CMD. It is the same as in Linux.
The CMD that you launched is alive=true but when you started java from that CMD is another process which is a child of the CMD but it will not return you the expected results.
HTH,
Gal
PS. you might want to take a look at https://commons.apache.org/proper/commons-exec/ which is superior in functionality to Java in my opinion.
I am trying to run maven command from java main but it is not working for me as desired.
When i run the below code it runs the maven command on the same existing project in which this main class residing, but i want to run this maven command from this class to any another project folder.
Please help!
Thanks in advance!
package com.codecoverage.runner;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MavenCoberturaRunner {
public static void main(String[] args) throws IOException, InterruptedException {
Process p = null;
try {
p = Runtime.getRuntime().exec("C:/apache-maven-2.0.9/apache-maven-2.0.9/bin/mvn.bat clean cobertura:cobertura -Dcobertura.report.format=xml");
} catch (IOException e) {
System.err.println("Error on exec() method");
e.printStackTrace();
}
copy(p.getInputStream(), System.out);
p.waitFor();
}
static void copy(InputStream in, OutputStream out) throws IOException {
while (true) {
int c = in.read();
if (c == -1)
break;
out.write((char) c);
}
}
}
You should use Runtime.exec(String command, String[] envp, File dir) method,
which executes the specified string command in a separate process with the specified environment and working directory.
What you want is to set working directory so it points to the place you need to run Maven at.
use -f in command line
C:/apache-maven-2.0.9/apache-maven-2.0.9/bin/mvn.bat -f path/to/your/pom.xml clean cobertura:cobertura -Dcobertura.report.format=xml
I have the following code segment to run a bat file:
String workingDir = System.getProperty("user.dir");
ProcessBuilder pb = new ProcessBuilder("cmd", "/c",
"\"" + workingDir + File.separator + "midl.bat\"");
Process ddsBuildProc = pb.start();
ddsBuildProc.waitFor();
The workingDir includes spaces in the path. Eventhough I use quotes to enclose the workingDir+fileName string, the shell still splits the workingDir and doesn't run the bat file. If a try and copy-paste-execute the bat file path string in the Windows command window manually, it works as expected. What can be the problem here?
Also, please do not close this question as duplicate because I tried all the solutions in the other questions with no success.
Don't quote commands in a command list, unless the command been executed expects it, this will just stuff things up
user.dir is your programs current executing context...so it actually makes no sense to include it, you could just use midl.bat by itself (assuming the command exists within the current execution context)
I wrote a really simple batch file...
#echo off
dir
Which I put in my "C:\Program Files" directory, as I need a path with spaces and used....
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RunBatch {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder(
"cmd", "/c", "listme.bat"
);
pb.directory(new File("C:/Program Files"));
pb.redirectError();
try {
Process process = pb.start();
InputStreamConsumer.consume(process.getInputStream());
System.out.println("Exited with " + process.waitFor());
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
public static class InputStreamConsumer implements Runnable {
private InputStream is;
public InputStreamConsumer(InputStream is) {
this.is = is;
}
public static void consume(InputStream inputStream) {
new Thread(new InputStreamConsumer(inputStream)).start();
}
#Override
public void run() {
int in = -1;
try {
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
To run it without any issues...