使用 ProcessBuilder 执行本机命令,适用于有限时间内返回结果,且返回结果内容不大(不会撑爆缓冲区),获取标准输出、错误输出:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.util.CollectionUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class ProcessUtil {
public enum StreamType {
OUTPUT,
INPUT,
ERROR
}
// 获得命令的执行输出流
public static List<String> bashResultSyn(String command) {
return bashFullSyn(command).get(StreamType.INPUT);
}
// 获得命令的执行错误流
public static List<String> bashErrorSyn(String command) {
return bashFullSyn(command).get(StreamType.ERROR);
}
public static Map<StreamType, List<String>> bashFullSyn(String command) {
Map<StreamType, List<String>> map = new HashMap<>();
try {
Process process = new ProcessBuilder("bash", "-c", command).start();
List<String> result = getProcessResult(process);
List<String> error = getProcessError(process);
int exitCode = process.waitFor();
map.put(StreamType.INPUT, result);
map.put(StreamType.ERROR, error);
exitCodeLog(exitCode, command, result, error);
} catch (IOException | InterruptedException e) {
log("command", command);
log.error(ExceptionUtils.getFullStackTrace(e));
} catch (Exception e) {
throw new RuntimeException(e);
}
return map;
}
private static void log(String key, Object value) {
log.info("{}:{}", key, value);
}
private static void exitCodeLog(int exitCode, String command, List<String> result, List<String> error) {
log("command", command);
if (result.size() < 100) {
for (String s : result) {
log.info(s);
}
} else {
log("result size", result.size());
}
if (!CollectionUtils.isEmpty(error)) {
log("exitCode", exitCode);
log("error", error);
}
}
private static List<String> getProcessResult(Process process) throws IOException {
return readStream(process.getInputStream());
}
private static List<String> getProcessError(Process process) throws IOException {
return readStream(process.getErrorStream());
}
private static List<String> readStream(InputStream inputStream) throws IOException {
List<String> lines = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
}
ssh执行远程主机命令,适用场景同上
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class LinuxUtil {
public static List<String> execCmd(String command, String host, String user, String password) {
log.info("host:{}, cmd:{}", host, command);
Session session = null;
ChannelExec channelExec = null;
try {
session = createSession(host, user, password);
channelExec = (ChannelExec) session.openChannel("exec");
channelExec.setCommand(command);
channelExec.setInputStream(null);
channelExec.setErrStream(System.err);
InputStream inputStream = channelExec.getInputStream();
InputStream errStream = channelExec.getErrStream();
channelExec.connect();
return getResult(inputStream, errStream);
} catch (JSchException | IOException e) {
List<String> errList = new ArrayList<>();
errList.add(e.getMessage());
return errList;
} finally {
if (channelExec != null) {
channelExec.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}
private static Session createSession(String host, String user, String password) throws JSchException {
JSch jsch = new JSch();
//获取sshSession
Session session = jsch.getSession(user, host, 22);
//添加密码
session.setPassword(password);
//严格主机密钥检查
session.setConfig("StrictHostKeyChecking", "no");
//开启sshSession连接
session.setTimeout(999999999);
session.connect();
return session;
}
// 合并输出流结果和错误流结果
private static List<String> getResult(InputStream inputStream, InputStream errStream) throws IOException {
List<String> result = readStream(inputStream);
List<String> error = readStream(errStream);
if (result.size() < 100) {
for (String s : result) {
log.info(s);
}
} else {
log.info("result size:{}", result.size());
}
if (!CollectionUtils.isEmpty(error)) {
log.error("error:{}", error);
}
result.addAll(error);
return result;
}
private static List<String> readStream(InputStream inputStream) throws IOException {
List<String> lines = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
}
jsch依赖
<dependency>
<groupId>com.github.mwiede</groupId>
<artifactId>jsch</artifactId>
<version>0.2.17</version>
</dependency>
检查远程主机是否可连接
boolean checkCoonServer(String host) {
try {
InetAddress coon = InetAddress.getByName(host);
return coon.isReachable(200);
} catch (IOException e) {
log.error("coonServer find IOException " + e.getMessage());
return false;
}
}
ssh到别的主机上执行ssh命令(交互式)
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class InteractiveCommandUtil {
public static final int SESSION_TIMEOUT = 60000;
public static final int CHANNEL_TIMEOUT = 60 * 20 * 1000;
public static void main(String[] args) throws Exception {
String host = "***";
String user = "***";
String password = "***";
try {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
session.setTimeout(SESSION_TIMEOUT);
session.setPassword(password);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
Channel channel = session.openChannel("shell");
channel.connect(CHANNEL_TIMEOUT);
InputStream inputStream = channel.getInputStream();
OutputStream outputStream = channel.getOutputStream();
sendCommand(outputStream, "ssh ***@*** date -R");
// Read the output
List<String> result1 = readOutput(inputStream);
if (linesContains(result1, "yes/no")) {
sendCommand(outputStream, "yes");
result1 = readOutput(inputStream);
}
if (linesContains(result1, "password")) {
sendCommand(outputStream, "***");
result1 = readOutput(inputStream);
}
readOutput(inputStream);
channel.disconnect();
session.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void sendCommand(OutputStream outputStream, String command) throws Exception {
outputStream.write((command + "\n").getBytes());
outputStream.flush();
Thread.sleep(1000); // Wait for command to execute (adjust as needed)
}
private static List<String> readOutput(InputStream inputStream) throws Exception {
byte[] buffer = new byte[1024];
int bytesRead;
List<String> result = new ArrayList<>();
while (inputStream.available() > 0 && (bytesRead = inputStream.read(buffer)) > 0) {
String s = new String(buffer, 0, bytesRead);
result.add(s);
System.out.print(s);
}
return result;
}
public static boolean linesContains(List<String> lines, String keyword) {
return lines.stream().anyMatch(t -> t.contains(keyword));
}
}
这一段参考的代码原型: