Run the command that displays the console window, and also process the process

I am trying to run a command from Java that will start a process that runs in a few minutes. I just need to run the command and get the process descriptor and continue with other operations in the loop. At certain intervals, I will need to make sure that the process is still active.

I also need a console window to display to show the result of the process to the user.

Currently, I tried methods from the Runtime and ProcessBuilder classes to run my team, but none of them helped me achieve my goal.

Code example:

//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 the live variable is True, but I do not see that the process has started. When the program is completed, only then the process begins, and I'm not sure why this is happening.

Also, to display the console window, I found from Google that I need to use the following command:

 String finalCmd = "cmd /c start cmd.exe /c \"" + cmd + "\""; 

However, the process starts immediately, but I do not get the process descriptor, because I find that the active variable shows false.

Does anyone know how this goal can be achieved? I am fine if this cannot be done at the same time, but at least I need to start the process in order to start it and get the handler to monitor the state of the process later in my code.

+5
source share
4 answers

It uses a solution using 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() : ""; } 

Output example

 Output from command: ProcessId = 6480; ProcessId is: 6480 Is process still running? true 

To show / display the 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"); 

Literature:

https://msdn.microsoft.com/en-us/library/aa394531(v=vs.85).aspx

https://www.computerhope.com/wmic.htm

+1
source

A couple of things that are going wrong here:

  • We need to pass our command as string tokens to the exec () command
  • We need to wait for the process to complete using process.waitFor () instead of the sleeping one, this will block the current thread, so if you do not want you to need to execute this on another thread or use the ExecutorService.
  • It is recommended to check the output value of waitFor () to see if our command was executed correctly (value 0) or not (any other value, usually positive 1 in case of unsuccessful execution)
  • Optionally (to see the result) we need to redirect the standard OUT and ERR somewhere, say, print it to console (), although you can put it in a file with some GUI, 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 this is recommended since JDK 1.5
  • read inputStream command

So, the code will look something 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 it in a separate thread or using the executing service. 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(); } 
+3
source

since I do not quite understand what you really need, I gave a comprehensive example of opening cmd from a java class (for example, class A) and starting a process of another Java class (class B) and performing some operation with class B, and class B informs the class And about whether it is processed or not. so the point is to exclude class B from the promt command that class A started and sent information from class B to A to notify her that it was still working.

in my example, I took the Main class as a class A and myProcess class as a class B. As you can see in the code below the Main class , this cmd opens and the myProcess class is myProcess class , and then myProcess class sends 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(); } } 

class myProcess:

since you need to compile the myProcess class manually using the command line and excecute the myProcess.class file from the main class

and class myProcess

 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.

0
source

I believe that you need to run the application as a process, not CMD, and then start the child CMD process. This is the same as Linux.

The created CMD is true = true, but when you started java from this CMD, this is another process that is a child of the CMD, but it will not return you the expected results.

NTN, Gal

PS. you can take a look at https://commons.apache.org/proper/commons-exec/ , which, in my opinion, is superior in functionality to Java.

0
source

Source: https://habr.com/ru/post/1275335/


All Articles