Java能够经过Runtime.getRuntime().exec()方法调用linux平台下的命令及Shell脚本。java
考虑到阻塞问题以及为了获取命令输出,文中使用了exitValue方法。linux
代码以下shell
ShellUtils:执行外部命令的工具类apache
package com.wll.shell; import com.wll.utils.CommonUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; public class ShellUtils { private static final Logger LOGGER = LoggerFactory.getLogger(ShellUtils.class); private static final long THREAD_SLEEP_TIME = 10; private static final int DEFAULT_WAIT_TIME = 20 * 60 * 1000; public static void runShell(String cmd) { String[] command = new String[]{"/bin/sh", "-c", cmd}; try { Process process = Runtime.getRuntime().exec(command); ShellResult result = getProcessResult(process, DEFAULT_WAIT_TIME); LOGGER.info("Command [{}] executed successfully.", cmd); LOGGER.info(result.toString()); } catch (IOException e) { e.printStackTrace(); } } /** * 获取命令执行结果 * @param process 子进程 * @param waitTime 指定超时时间 * @return 命令执行输出结果 */ public static ShellResult getProcessResult(Process process, long waitTime) { ShellResult cmdResult = new ShellResult(); boolean isTimeout = false; long loopNumber = waitTime / THREAD_SLEEP_TIME; long realLoopNumber = 0; int exitValue = -1; StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream()); StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream()); errorGobbler.start(); outputGobbler.start(); try { while (true) { try { Thread.sleep(THREAD_SLEEP_TIME); exitValue = process.exitValue(); break; } catch (InterruptedException e) { realLoopNumber++; if (realLoopNumber >= loopNumber) { isTimeout = true; break; } } } errorGobbler.join(); outputGobbler.join(); if (isTimeout) { cmdResult.setErrorCode(ShellResult.TIMEOUT); return cmdResult; } cmdResult.setErrorCode(exitValue); if (exitValue != ShellResult.SUCCESS) { cmdResult.setDescription(errorGobbler.getOutput()); } else { cmdResult.setDescription(outputGobbler.getOutput()); } } catch (InterruptedException e) { LOGGER.error("Get shell result error."); cmdResult.setErrorCode(ShellResult.ERROR); } finally { CommonUtils.closeStream(process.getErrorStream()); CommonUtils.closeStream(process.getInputStream()); CommonUtils.closeStream(process.getOutputStream()); } return cmdResult; } }
StreamGobbler:读取命令输出流和错误流的工具类ide
package com.wll.shell; import com.wll.utils.CommonUtils; import java.io.*; import java.util.ArrayList; import java.util.List; public class StreamGobbler extends Thread { private InputStream is; private List<String> output = new ArrayList<String>(); public StreamGobbler(InputStream is) { this.is = is; } public List<String> getOutput() { return output; } @Override public void run() { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); String line = ""; while ((line = reader.readLine()) != null) { output.add(line); } } catch (IOException e) { e.printStackTrace(); } finally { CommonUtils.closeStream(reader); } } }
ShellResult:命令执行结果工具
package com.wll.shell; import java.util.List; public class ShellResult { public static final int SUCCESS = 0; public static final int ERROR = 1; public static final int TIMEOUT = 13; private int errorCode; private List<String> description; public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } public List<String> getDescription() { return description; } public void setDescription(List<String> description) { this.description = description; } @Override public String toString() { return "ShellResult{" + "errorCode=" + errorCode + ", description=" + description + '}'; } }
ShellTest:测试类oop
package com.wll.shell; public class ShellTest { public static void main(String[] args) { String cmd = ""; if (args.length == 1) { cmd = args[0]; } ShellUtils.runShell(cmd); } }
另外,因为流关闭操做用得比较频繁,故单独写了个工具类。测试
package com.wll.utils; import org.apache.log4j.Logger; import java.io.Closeable; import java.io.IOException; public class CommonUtils { private static final Logger LOGGER = Logger.getLogger(CommonUtils.class); /** * 提供统一关闭流的方法 * * @param stream 待关闭的流 */ public static void closeStream(Closeable stream) { if (stream == null) { return; } try { stream.close(); } catch (IOException e) { LOGGER.error("Close stream failed!"); } } }
代码放在CentOS下,详细目录结构以下:this
如下为测试脚本,十分简单,只是输出当前日期和时间线程
最终运行结果以下: