package com.utils;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Date;
public class CommandUtils {
private static final Logger LOG = LoggerFactory.getLogger(CommandUtils.class);
private static Boolean isWinOS() {
return System.getProperty("os.name").toLowerCase().startsWith("win");
}
private static Boolean isMacOS() {
return System.getProperty("os.name").toLowerCase().startsWith("mac");
}
private static Process doExecute(String shell, String outputFile, boolean withDetails, boolean append) throws Exception {
String command = shell;
if (StringUtils.isNotEmpty(outputFile)) {
if (withDetails) {
String commandLog = String.format("\n%s: %s", DateFormatUtils.format(new Date(), "yyyy-MM-dd'T'HH:mm:ss"), command);
FileUtils.writeStringToFile(new File(outputFile), commandLog, StandardCharsets.UTF_8, append);
command += " 1>>" + outputFile + " 2>&1";
} else {
if (append) {
command += " 1>>" + outputFile + " 2>&1";
} else {
command += " 1>" + outputFile + " 2>&1";
}
}
}
File shellFile = new File(String.format("%s/%d_%s.sh", "/tmp/shell", System.currentTimeMillis(), RandomUtils.randomStr(4)));
FileUtils.writeStringToFile(shellFile, command, StandardCharsets.UTF_8, false);
return Runtime.getRuntime().exec("sh " + shellFile.getAbsolutePath());
}
private static String getPid(Process process) throws Exception {
if (process.getClass().getName().contains("UNIXProcess")) {
// linux获取进程id
Field pidField = process.getClass().getDeclaredField("pid");
pidField.setAccessible(true);
return String.valueOf(pidField.get(process));
} else {
// window获取进程id
Field handleField = process.getClass().getDeclaredField("handle");
handleField.setAccessible(true);
long handle = handleField.getLong(process);
Kernel32 kernel = Kernel32.INSTANCE;
WinNT.HANDLE windNTHandle = new WinNT.HANDLE();
windNTHandle.setPointer(Pointer.createConstant(handle));
return String.valueOf(kernel.GetProcessId(windNTHandle));
}
}
/**
* 执行命令行
*
* @param shell
* @param outputFile
* @return
* @throws IOException
*/
public static String execute(String shell, String outputFile, boolean withDetails, boolean append) throws Exception {
Process process = doExecute(shell, outputFile, withDetails, append);
String pid = getPid(process);
if (StringUtils.isNotEmpty(outputFile) && withDetails) {
FileUtils.writeStringToFile(new File(outputFile), "\npid: " + pid, StandardCharsets.UTF_8, true);
}
return pid;
}
/**
* 根据pid判断进程是否存在,如果存在,杀掉进程,并清空文件夹
*
* @param pid
* @return 0表示不存在,1表示存在,因为进程号不可能重复,所以输出肯定非0即1
*/
public static boolean existPid(String pid) {
if (StringUtils.isEmpty(pid)) {
return false;
}
try {
BufferedReader bufferedReader = null;
try {
String command = "ps -ef | awk '{print $2}' | grep -w '" + pid + "' | wc -l";
if (isWinOS()) {
command = "ps --no-heading " + pid + " | wc -l";
}
Process process = doExecute(command, null, false, false);
if (process != null) {
//bufferedReader用于读取Shell的输出内容
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "gbk"), 1024);
process.waitFor();
}
String line;
//读取Shell的输出内容,并添加到stringBuffer中
StringBuilder output = new StringBuilder();
while (bufferedReader != null && (line = bufferedReader.readLine()) != null) {
output.append(line).append("\n");
}
if (StringUtils.isNotEmpty(output.toString())) {
int outputNum = Integer.valueOf(output.toString().trim());
return outputNum == 1;
}
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (Exception e) {
// ignore exception
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 杀掉进程
*
* @param pid
* @return true, 命令执行成功
*/
public static void killByPid(String pid, boolean withSubProcess) throws Exception {
if (existPid(pid)) {
String command = "kill -9 " + pid;
if (withSubProcess) {
command = String.format("ps --ppid %s | awk '{if($1~/[0-9]+/) print $1}' | xargs kill -9 && kill -9 %s", pid, pid);
}
Process process = doExecute(command, null, false, false);
process.waitFor();
process.destroy();
LOG.info(String.format("kill process, pid:%s", pid));
}
}
}