在 Java 中可以通过 SSH2 协议远程执行 Linux 系统的命令或 Shell 脚本。

添加依赖

需添加 ganymed-ssh2-262.jarcommons-io-2.6.jarcommons-lang3-3.9.jarfastjson-1.2.58.jar包,Maven 依赖如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- https://mvnrepository.com/artifact/ch.ethz.ganymed/ganymed-ssh2 -->
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>262</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>

api 说明

  1. 首先构造一个连接器,传入一个需要登陆的ip地址;

    Connection conn = new Connection(hostname);

  2. 模拟登陆目的服务器,传入用户名和密码;

    boolean isAuthenticated = conn.authenticateWithPassword(username, password);

    它会返回一个布尔值,true 代表成功登陆目的服务器,否则登陆失败。

  3. 打开一个session,执行你需要的linux 脚本命令;

    Session session = conn.openSession();
    session.execCommand(“ifconfig”);

  4. 接收目标服务器上的控制台返回结果,读取br中的内容;

    InputStream stdout = new StreamGobbler(sess.getStdout());
    BufferedReader br = new BufferedReader(new InputStreamReader(stdout));

  5. 得到脚本运行成功与否的标志 :0-成功 非0-失败

    System.out.println(“ExitCode: ” + sess.getExitStatus());

  6. 关闭session和connection

    sess.close();
    conn.close();

备注

1、通过第2步认证成功后,当前目录就位于/home/username/目录之下,你可以指定脚本文件所在的绝对路径,或者通过cd导航到脚本文件所在的目录,然后传递执行脚本所需要的参数,完成脚本调用执行。

2、执行脚本以后,可以获取脚本执行的结果文本,需要对这些文本进行正确编码后返回给客户端,避免乱码产生。

3、如果你需要执行多个linux控制台脚本,比如第一个脚本的返回结果是第二个脚本的入参,你必须打开多个Session,也就是多次调用
Session sess = conn.openSession();,使用完毕记得关闭就可以了。

实例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import com.alibaba.fastjson.util.IOUtils;
import org.apache.commons.lang3.StringUtils;

/**
* 远程执行Linux命令
*
* @author 92481
*
*/
public class RemoteExecuteCommand {
// 字符编码默认是utf-8
private static String DEFAULTCHART = "UTF-8";
private Connection conn;
private String ip;
private String userName;
private String userPwd;

public RemoteExecuteCommand(String ip, String userName, String userPwd) {
this.ip = ip;
this.userName = userName;
this.userPwd = userPwd;
}

public RemoteExecuteCommand() {

}

/**
* 远程登录linux主机
* @return 登录成功返回true,否则返回false
* @throws Exception
*/
public Boolean login() throws Exception {
boolean flg = false;
try {
conn = new Connection(ip);
// 连接
conn.connect();
// 认证
flg = conn.authenticateWithPassword(userName, userPwd);
} catch (IOException e) {
throw new Exception("远程连接服务器失败", e);
}
return flg;
}

/**
* 远程执行shll脚本或者命令
* @param cmd 即将执行的命令
* @return 命令执行完后返回的结果值
* @throws Exception
*/
public String execute(String cmd) throws Exception {
String result = "";
Session session = null;
try {
if (login()) {
// 打开一个会话
session = conn.openSession();
// 执行命令
session.execCommand(cmd);
result = processStdout(session.getStdout(), DEFAULTCHART);
// 如果为输出为空,说明脚本执行出错了
if (StringUtils.isBlank(result)) {
result = processStdout(session.getStderr(), DEFAULTCHART);
}
conn.close();
session.close();
}
} catch (IOException e) {
throw new Exception("命令执行失败", e);
} finally {
if (conn != null) {
conn.close();
}
if (session != null) {
session.close();
}
}
return result;
}

/**
* 解析脚本执行返回的结果集
* @param in 输入流对象
* @param charset 编码
* @return 以纯文本的格式返回
* @throws Exception
*/
private String processStdout(InputStream in, String charset)
throws Exception {
InputStream stdout = new StreamGobbler(in);
StringBuffer buffer = new StringBuffer();
InputStreamReader isr = null;
BufferedReader br = null;
try {
isr = new InputStreamReader(stdout, charset);
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
buffer.append(line + "\n");
}
} catch (UnsupportedEncodingException e) {
throw new Exception("不支持的编码字符集异常", e);
} catch (IOException e) {
throw new Exception("读取指纹失败", e);
} finally {
IOUtils.close(br);
IOUtils.close(isr);
IOUtils.close(stdout);
}
return buffer.toString();
}

public static void main(String[] args) throws Exception {
String linuxIP = "172.18.195.253";
String usrName = "root";
String passwd = "Jufeng2010";
RemoteExecuteCommand rec = new RemoteExecuteCommand(linuxIP, usrName, passwd);
// 执行命令
System.out.println(rec.execute("ip a"));
// 执行脚本
// rec.execute("sh /etc/init.d/domain.sh hkc.demo.sunsheen.cn 172.18.195.155 8888");
}
}

例如:

1
2
3
// 执行脚本 (域名访问)
rec.execute("sh /etc/init.d/domain.sh " + domainBef+domainLater + " " + ip + " " +
innerPort + " " + createUserName);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cd /etc/init.d/domain.sh

cd /etc/nginx/conf.d/
# 创建配置文件
touch $1_$4.conf;
# 像配置文件写入内容
echo "server {
listen 80;
server_name $1;
location / {
proxy_pass http://$2:$3;
proxy_set_header Host \$host:80;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header Via \"nginx\";
}
}" > $1_$4.conf;
# 重启nginx
nginx -s reload;