@TedZhou
2020-08-25T03:05:06.000000Z
字数 4121
阅读 979
java commons exec shell process
Java创建子进程(Process)执行外部命令底层的方法是new ProcessBuilder().start()或Runtime.getRuntime().exec()。
Apache commons-exec对底层进行封装,提供了更加详细的设置和监控方法。
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-exec</artifactId><version>1.3</version></dependency>
import java.io.IOException;import java.io.OutputStream;import java.util.concurrent.CompletableFuture;import org.apache.commons.exec.CommandLine;import org.apache.commons.exec.DefaultExecutor;import org.apache.commons.exec.ExecuteWatchdog;import org.apache.commons.exec.PumpStreamHandler;import org.apache.commons.exec.ShutdownHookProcessDestroyer;public class CmdHelper {/*** 执行外部命令,等待返回结果** @param commandLine: 命令行* @param out: 输出流,为空默认标准输出* @param timeout: 超时,不大于0则不限超时* @return CmdHandler based on DefaultExecuteResultHandler*/public static CmdHandler run(CommandLine commandLine, OutputStream out, long timeout) {PumpStreamHandler pumpStreamHandler = null;if (null == out) {pumpStreamHandler = new PumpStreamHandler();} else {pumpStreamHandler = new PumpStreamHandler(out);}DefaultExecutor executor = new DefaultExecutor();CmdHandler cmdHandler = new CmdHandler(executor);executor.setStreamHandler(pumpStreamHandler);ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();executor.setProcessDestroyer(processDestroyer);// 随主进程退出if (timeout <= 0) {timeout = ExecuteWatchdog.INFINITE_TIMEOUT;}ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout);executor.setWatchdog(watchdog);// 控制超时try {executor.execute(commandLine, cmdHandler);cmdHandler.waitFor();// 等待返回结果} catch (IOException | InterruptedException e) {e.printStackTrace();}return cmdHandler;}/*** 异步执行外部命令** @param commandLine: 命令行* @param out: 输出流,为空默认标准输出* @param timeout: 超时,不大于0则不限超时* @return CompletableFuture<CmdHandler>*/public static CompletableFuture<CmdHandler> exec(CommandLine commandLine, OutputStream out, long timeout) {CompletableFuture<CmdHandler> cf = new CompletableFuture<>();PumpStreamHandler pumpStreamHandler = null;if (null == out) {pumpStreamHandler = new PumpStreamHandler();} else {pumpStreamHandler = new PumpStreamHandler(out);}DefaultExecutor executor = new DefaultExecutor();CmdHandler cmdHandler = new CmdHandler(executor);cmdHandler.setCallback(() -> {cf.complete(cmdHandler);// 执行完成后回调});executor.setStreamHandler(pumpStreamHandler);ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();executor.setProcessDestroyer(processDestroyer);// 随主进程退出if (timeout <= 0) {timeout = ExecuteWatchdog.INFINITE_TIMEOUT;}ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout);executor.setWatchdog(watchdog);// 控制超时try {executor.execute(commandLine, cmdHandler);} catch (IOException e) {e.printStackTrace();}return cf;}public static void main(String[] args) throws InterruptedException {CommandLine command = CommandLine.parse("ping 127.0.0.1 -t");// 测试同步执行CmdHandler result = CmdHelper.run(command, null, 3000);System.out.println(result.resultString());// 测试异步执行CmdHelper.exec(command, null, 0).thenAccept(cmdHandler -> {System.out.println(cmdHandler.resultString());});}}
import org.apache.commons.exec.DefaultExecuteResultHandler;import org.apache.commons.exec.ExecuteException;import org.apache.commons.exec.ExecuteWatchdog;import org.apache.commons.exec.Executor;public class CmdHandler extends DefaultExecuteResultHandler {Executor executor;Runnable callback;public CmdHandler(Executor executor) {this.executor = executor;}public void setCallback(Runnable callback) {this.callback = callback;}public Executor getExecutor() {return this.executor;}public ExecuteWatchdog getWatchdog() {if (this.executor == null) return null;return this.executor.getWatchdog();}public String resultString() {String retMsg = "complete";if (this.getException() != null) {ExecuteWatchdog watchdog = this.getWatchdog();if (watchdog != null && watchdog.killedProcess()) {retMsg = "timeout";} else {retMsg = this.getException().getMessage();}}return this.getExitValue() + ":" + retMsg;}@Overridepublic void onProcessComplete(int exitValue) {super.onProcessComplete(exitValue);if (callback != null) {callback.run();}}@Overridepublic void onProcessFailed(ExecuteException e) {super.onProcessFailed(e);if (callback != null) {callback.run();}}}