一 执行单条管道命令
适用于单个管道命令的场景,如查进程、杀进程、全局命令等的调用;
/**
* 单条管道命令
* @param command 单条管道命令
*/
public static void executeCMD(String command) {
String safeCommand = getSafeCommand(command, "/bin/sh -c ");
Process pr = null;
try {
pr = Runtime.getRuntime().exec(safeCommand, null, new File(Constants.PATH_SLASH));
// 读取输出,脚本运行结束后获取返回值
// 防阻塞,起独立线程获取输出流及错误流
getInputStreamResponse(pr.getInputStream(), "InputStream");
getInputStreamResponse(pr.getErrorStream(), "ErrorStream");
// 等待进程执行结束并销毁
pr.waitFor();
} catch (IOException | InterruptedException e) {
throw new RuntimeException("executeCMD process error", e);
} finally {
pr.destroy();
}
}
private static void getInputStreamResponse(InputStream is, String streamType) {
new Thread(() -> {
try {
BufferedReader stdInput = new BufferedReader(new InputStreamReader(is));
StringBuffer strBuf = new StringBuffer();
String line;
while ((line = stdInput.readLine()) != null) {
log.info(line);
}
} catch (Exception e) {
log.error(e);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
上述代码存在的缺陷:
1、管道命令之间相互独立,上述方法不支持执行连续管道命令,eg:1、cd 目录 2、./test.sh,此场景考虑使用下述批量管道命令执行方式;
2、遗留问题:上述方法中由于使用了Thread打印流日志,可能会导致主方法executeCMD()调用到pr.destroy();时独立线程中流日志尚未输出结束,此时getInputStreamResponse()方法中会报 stream closed的异常,由于我的业务中不关注输出结果,所以此问题暂未修复,有需要的小伙伴麻烦自行解决啦;
二 批量管道命令
适用于相互之间有依赖性的命令执行,如先进入某个目录,再在此目录下执行命令的场景;
/**
* 批量执行管道命令
* @param commands 批量管道命令
*/
public static void executeBatchCMD(String[] commands) {
Runtime run = Runtime.getRuntime();
File wd = new File("/bin");
Process proc = null;
try {
proc = run.exec("/bin/bash", null, wd);
} catch (IOException e) {
e.printStackTrace();
}
if (proc != null) {
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
for (String command : commands) {
out.println(getSafeCommand(command, ""));
}
out.println(getSafeCommand("exit", ""));
try {
String line;
while ((line = in.readLine()) != null) {
log.info(line);
}
proc.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {}
out.close();
proc.destroy();
}
}
}
三 管道命令白名单配置
主要是为了防止命令注入,所以加个白名单配置
/**
* 管道命令白名单
* @param command 管道命令
* @param suffix
* @return
*/
public static String getSafeCommand(String command, String suffix) {
//command = "/bin/sh -c "+command;
command = suffix + command;
StringBuffer safeCommand = new StringBuffer();
String whiteList = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-=[]\\',./";
char[] safeCommandChars = command.toCharArray();
for (int i = 0, length = safeCommandChars.length; i < length; i++) {
int whiteListIndex = whiteList.indexOf(safeCommandChars[i]);
if (-1 == whiteListIndex) {
return safeCommand.toString();
}
safeCommand.append(whiteList.charAt(whiteListIndex));
}
return safeCommand.toString();
}
版权声明:本文为sxg0205原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。