首先创建springboot项目
shell脚本
这里是执行本地脚本
#!/bin/sh
echo 'Hello World!'
然后编写执行shell脚本的util类
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class ShellUtils {
/**
* @param pathOrCommand 脚本路径或者命令
* @return
*/
public static List<String> exceShell(String pathOrCommand) {
List<String> result = new ArrayList<>();
try {
// 执行脚本
Process ps = Runtime.getRuntime().exec(pathOrCommand);
int exitValue = ps.waitFor();
if (0 != exitValue) {
System.out.println("call shell failed. error code is :" + exitValue);
}
// 只能接收脚本echo打印的数据,并且是echo打印的最后一次数据
BufferedInputStream in = new BufferedInputStream(ps.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
System.out.println("脚本返回的数据如下: " + line);
result.add(line);
}
in.close();
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
最后开发接口调用此类
@RestController
@RequestMapping("/shell/test")
public class ShellTestController {
@GetMapping("/shell")
public List<String> shellTest(){
List<String> list = ShellUtils.exceShell("/home/shelltest/test.sh");
return list;
}
}
如何执行远程脚本
在这里我试用了三种方式,实现远程脚本的执行
但是使用ssh2时
java.io.IOException: Key exchange was not finished, connection is closed.
at ch.ethz.ssh2.transport.KexManager.getOrWaitForConnectionInfo(KexManager.java:75)
at ch.ethz.ssh2.transport.TransportManager.getConnectionInfo(TransportManager.java:169)
at ch.ethz.ssh2.Connection.connect(Connection.java:759)
at ch.ethz.ssh2.Connection.connect(Connection.java:628)
at com.zhou.util.SSHClient.login(SSHClient.java:39)
at com.zhou.util.SSHClient.exec(SSHClient.java:47)
at com.zhou.util.SSHClient.main(SSHClient.java:76)
Caused by: java.io.IOException: Cannot negotiate, proposals do not match.
at ch.ethz.ssh2.transport.ClientKexManager.handleMessage(ClientKexManager.java:123)
at ch.ethz.ssh2.transport.TransportManager.receiveLoop(TransportManager.java:572)
at ch.ethz.ssh2.transport.TransportManager$1.run(TransportManager.java:261)
at java.lang.Thread.run(Thread.java:745)
会抛出上述的异常,大体的意思就是密钥交换算法不匹配,导致连接失败。
但是老版本的centos系统还是可以使用的
此版本使用没有问题 ,下面是代码
引入的maven
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>262</version>
</dependency>
package com.zhou.util;
import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
public class SSHClient {
private String ip;
private String username;
private String password;
private String charset = Charset.defaultCharset().toString();
private static final int TIME_OUT = 1000 * 5 * 60;
private Connection conn;
public SSHClient(String ip, String username, String password) {
this.ip = ip;
this.username = username;
this.password = password;
}
/**
* 登录指远程服务器
* @return
* @throws IOException
*/
private boolean login() throws IOException {
conn = new Connection(ip);
conn.connect();
return conn.authenticateWithPassword(username, password);
}
public List<String> exec(String shell) throws Exception {
List<String> result = new ArrayList<>();
int ret = -1;
try {
if (login()) {
Session session = conn.openSession();
session.execCommand(shell);
session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
ret = session.getExitStatus();
// 只能接收脚本echo打印的数据,并且是echo打印的最后一次数据
BufferedInputStream in = new BufferedInputStream(session.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
System.out.println("脚本返回的数据如下: " + line);
result.add(line);
}
in.close();
br.close();
} else {
throw new Exception("登录远程机器失败" + ip); // 自定义异常类 实现略
}
} finally {
if (conn != null) {
conn.close();
}
}
return result;
}
public static void main(String[] args) {
try {
SSHClient sshClient = new SSHClient("192.168.0.1", "root", "123456");
List<String> exec = sshClient.exec("/home/shell/run_all.sh");
for (String s : exec) {
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用sshd可以正常进行远程执行shell文件
maven代码
<!-- ssh-core start-->
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>net.i2p.crypto</groupId>
<artifactId>eddsa</artifactId>
<version>0.3.0</version>
</dependency>
<!-- ssh-core end-->
package com.zhou.util.sshcore;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ClientChannelEvent;
import org.apache.sshd.client.future.ConnectFuture;
import org.apache.sshd.client.session.ClientSession;
import java.io.ByteArrayOutputStream;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class SshSelfDemo {
public static String runCommand(String hostName,String userName,String pwd,int port,String cmd, long timeout)
throws Exception {
SshClient client = SshClient.setUpDefaultClient();
try {
// Open the client
client.start();
// Connect to the server
ConnectFuture cf = client.connect(userName, hostName, port);
ClientSession session = cf.verify().getSession();
session.addPasswordIdentity(pwd);
session.auth().verify();
// Create the exec and channel its output/error streams
ChannelExec ce = session.createExecChannel(cmd);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
ce.setOut(out);
ce.setErr(err);
// Execute and wait
ce.open();
Set<ClientChannelEvent> events =
ce.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(timeout));
session.close(false);
return out.toString();
} finally {
client.stop();
}
}
public static void main(String[] args) throws Exception{
String hostName = "192.168.0.1";
String userName = "root";
String pwd = "123456";
int port = 22;
SshConnection conn = new SshConnection(userName,pwd,hostName);
// &&-表示前面命令执行成功在执行后面命令; ||表示前面命令执行失败了在执行后面命令; ";"表示一次执行两条命令
String cmd = "/home/shell/run_all.sh";
String result = runCommand(hostName,userName,pwd,port,cmd,15);
System.out.println("===返回结果===>"+result);
// runCommandForInteractive(conn,15);
}
}
使用jsch也可以正常执行shell文件
maven依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
代码文章来源:https://www.toymoban.com/news/detail-621661.html
package com.zhou.util.sshcore;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.Properties;
public class JSchExecShellUtil {
private static final Logger logger = LoggerFactory.getLogger(JSchExecShellUtil.class);
public static String execShell(String hostName,String userName,String pwd,int port,String command, int timeout){
// 创建JSch对象
JSch jSch = new JSch();
Session jSchSession = null;
Channel jschChannel = null;
// 存放执行命令结果
StringBuffer result = new StringBuffer();
int exitStatus = 0;
try {
// 根据主机账号、ip、端口获取一个Session对象
jSchSession = jSch.getSession(userName, hostName, port);
// 存放主机密码
jSchSession.setPassword(pwd);
// 去掉首次连接确认
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
jSchSession.setConfig(config);
// 超时连接时间为3秒
jSchSession.setTimeout(timeout);
// 进行连接
jSchSession.connect();
jschChannel = jSchSession.openChannel("exec");
((ChannelExec) jschChannel).setCommand(command);
jschChannel.setInputStream(null);
// 错误信息输出流,用于输出错误的信息,当exitstatus<0的时候
((ChannelExec)jschChannel).setErrStream(System.err);
// 执行命令,等待执行结果
jschChannel.connect();
// 获取命令执行结果
InputStream in = jschChannel.getInputStream();
/**
* 通过channel获取信息的方式,采用官方Demo代码
*/
byte[] tmp=new byte[1024];
while(true){
while(in.available() > 0){
int i = in.read(tmp, 0, 1024);
if (i < 0) {
break;
}
result.append(new String(tmp, 0, i));
}
// 从channel获取全部信息之后,channel会自动关闭
if(jschChannel.isClosed()){
if (in.available() > 0) {
continue;
}
exitStatus = jschChannel.getExitStatus();
break;
}
try{Thread.sleep(1000);}catch(Exception ee){}
}
} catch (Exception e) {
logger.warn(e.getMessage());
} finally {
// 关闭sftpChannel
if (jschChannel != null && jschChannel.isConnected()) {
jschChannel.disconnect();
}
// 关闭jschSesson流
if (jSchSession != null && jSchSession.isConnected()) {
jSchSession.disconnect();
}
}
logger.info("获取执行命令的结果结果:"+result);
logger.info("退出码为:"+exitStatus);
return result.toString();
}
public static void main(String[] args) {
String username = "root";
String password = "123456";
String host = "192.168.0.1";
int port = 22;
String commond = "/home/shell/run_all.sh";
execShell(host,username,password, port, commond, 1000);
}
}
以上是整理的Java远程调用以及本地调用的代码实现文章来源地址https://www.toymoban.com/news/detail-621661.html
到了这里,关于springboot通过接口执行本地shell脚本的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!