我正在尝试从Java运行一个命令,它将启动一个运行几分钟的进程。我需要触发命令并获取进程句柄并继续循环中的其他操作。我会定期监控该过程是否仍处于活动状态。
我还需要显示控制台窗口以显示用户的流程输出。
目前,我已尝试运行Runtime和ProcessBuilder类的方法来运行我的命令,但它们都没有帮助我实现我的目标。
示例代码:
//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();
变量alive的值为True,但我没有看到该过程已开始。程序执行完成后,只有这个过程开始,我不确定为什么会这样。
同样为了显示控制台窗口,我从谷歌发现我需要使用以下命令:
String finalCmd = "cmd /c start cmd.exe /c \"" + cmd + "\"";
然而,有了这个,进程立即开始,但我没有得到进程句柄,因为我发现alive变量显示为false。
有人知道如何实现这一目标吗?如果不可能同时执行这两个操作,我很好,但至少我需要启动进程执行并获取句柄以便稍后在我的代码中监视进程状态。
答案 0 :(得分:3)
这里发生的事情不正确:
因此,以下代码至少应该起作用:
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);
进一步的建议:
所以代码会看起来像这样:
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);
由于waitFor()是一个阻塞调用,您可以在单独的线程中或使用executorService执行此操作。示例代码:
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();
}
答案 1 :(得分:1)
这是一个使用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 from command: ProcessId = 6480;
ProcessId is: 6480
Is process still running? true
要显示/显示cmd控制台,请将某些行更改为:
// Execution
String your_command = "cmd.exe /c \"dir\"";
process = Runtime.getRuntime().exec("cmd /c wmic process call create \"" + your_command + "\" | findstr ProcessId");
参考文献:
https://msdn.microsoft.com/en-us/library/aa394531(v=vs.85).aspx
答案 2 :(得分:0)
因为我不太了解你真正需要什么,所以我带来了一个从java类(例如类A)打开cmd并启动另一个java类(类B)的进程并从中执行某些操作的全面示例B类,而B类告知A类是否正在处理。所以整个事情是从A类开始的命令提示中排除B类,并将信息从B类发送到A以通知它它仍在运行。
在我的示例中,我将Main class
作为A类,将myProcess class
作为B类。
您可以在下面的代码中看到Main class
正在打开cmd并正在执行myProcess class
,然后myProcess class
正在通过Main class
<中创建的套接字发送有关该进程的信息/ p>
//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类:
顺便提一下,你需要通过命令提示符手动编译myProcess类,并从Main类中取出myProcess.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");
}
}
}
因为我并不完全理解你想要的东西,这可能不是你想要的,但是......如果你操纵代码,它肯定会对你有帮助。
答案 3 :(得分:0)
我认为您需要启动应用程序作为进程而不是CMD,然后启动CMD的子进程。它与Linux中的相同。
您启动的CMD是alive = true但是当您从该CMD启动java时,另一个进程是CMD的子进程,但它不会返回预期的结果。
HTH, 伽
PS。你可能想看一下https://commons.apache.org/proper/commons-exec/,我认为它在功能上优于Java。