广告位联系
返回顶部
分享到

Java JSch远程执行Shell命令的方法

java 来源:互联网 作者:秩名 发布时间:2022-02-24 13:28:51 人浏览
摘要

背景 项目需求,需要远程 ssh 登录到某个节点执行 shell 命令来完成任务。对于这种需求,如果不用 java 程序,直接 linux 的 ssh 命令就可以完成,但是在编码到程序中时需要相关的程序包

背景

项目需求,需要远程 ssh 登录到某个节点执行 shell 命令来完成任务。对于这种需求,如果不用 java 程序,直接 linux 的 ssh 命令就可以完成,但是在编码到程序中时需要相关的程序包来完成,本文主要介绍在 java 中如何使用 JSch 包实现 ssh 远程连接并执行命令。

JSch 简介

JSch 是Java Secure Channel的缩写。JSch是一个SSH2的纯Java实现。它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等,当然你也可以集成它的功能到你自己的应用程序。框架jsch很老的框架,更新到2016年,现在也不更新了。

JSch 使用 shell 执行命令,有两种方法

  • ChannelExec: 一次执行一条命令,一般我们用这个就够了。
  • ChannelShell: 可执行多条命令,平时开发用的不多,根据需要来吧;

1

2

ChannelExec channelExec = (ChannelExec) session.openChannel("exec");//只能执行一条指令(也可执行符合指令)

ChannelShell channelShell = (ChannelShell) session.openChannel("shell");//可执行多条指令 不过需要输入输出流

1. ChannelExec

每个命令之间用 ; 隔开。说明:各命令的执行给果,不会影响其它命令的执行。换句话说,各个命令都会执行,但不保证每个命令都执行成功。
每个命令之间用 && 隔开。说明:若前面的命令执行成功,才会去执行后面的命令。这样可以保证所有的命令执行完毕后,执行过程都是成功的。
每个命令之间用 || 隔开。说明:|| 是或的意思,只有前面的命令执行失败后才去执行下一条命令,直到执行成功一条命令为止。

2. ChannelShell

对于ChannelShell,以输入流的形式,可执行多条指令,这就像在本地计算机上使用交互式shell(它通常用于:交互式使用)。如要要想停止,有两种方式:

发送一个exit命令,告诉程序本次交互结束;
使用字节流中的available方法,来获取数据的总大小,然后循环去读。

使用示例

1. 引入 pom 依赖

1

2

3

4

5

<dependency>

   <groupId>com.jcraft</groupId>

   <artifactId>jsch</artifactId>

   <version>0.1.53</version>

</dependency>

2. jsch 使用示例

在此封装了一个 Shell 工具类,用来执行 shell 命令,具体使用细节在代码注释中有说明,可以直接拷贝并使用,代码如下:

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

package org.example.shell;

/**

 * Created by qianghaohao on 2021/3/28

 */

 

 

import com.jcraft.jsch.ChannelExec;

import com.jcraft.jsch.JSch;

import com.jcraft.jsch.Session;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

 

/**

 * @description:

 * @author: qianghaohao

 * @time: 2021/3/28

 */

public class Shell {

    private String host;

    private String username;

    private String password;

    private int port = 22;

    private int timeout = 60 * 60 * 1000;

 

    public Shell(String host, String username, String password, int port, int timeout) {

        this.host = host;

        this.username = username;

        this.password = password;

        this.port = port;

        this.timeout = timeout;

    }

 

    public Shell(String host, String username, String password) {

        this.host = host;

        this.username = username;

        this.password = password;

    }

 

    public String execCommand(String cmd) {

        JSch jSch = new JSch();

        Session session = null;

        ChannelExec channelExec = null;

        BufferedReader inputStreamReader = null;

        BufferedReader errInputStreamReader = null;

        StringBuilder runLog = new StringBuilder("");

        StringBuilder errLog = new StringBuilder("");

        try {

            // 1. 获取 ssh session

            session = jSch.getSession(username, host, port);

            session.setPassword(password);

            session.setTimeout(timeout);

            session.setConfig("StrictHostKeyChecking", "no");

            session.connect();  // 获取到 ssh session

 

            // 2. 通过 exec 方式执行 shell 命令

            channelExec = (ChannelExec) session.openChannel("exec");

            channelExec.setCommand(cmd);

            channelExec.connect();  // 执行命令

 

            // 3. 获取标准输入流

            inputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));

            // 4. 获取标准错误输入流

            errInputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getErrStream()));

 

            // 5. 记录命令执行 log

            String line = null;

            while ((line = inputStreamReader.readLine()) != null) {

                runLog.append(line).append("\n");

            }

 

            // 6. 记录命令执行错误 log

            String errLine = null;

            while ((errLine = errInputStreamReader.readLine()) != null) {

                errLog.append(errLine).append("\n");

            }

 

            // 7. 输出 shell 命令执行日志

            System.out.println("exitStatus=" + channelExec.getExitStatus() + ", openChannel.isClosed="

                    + channelExec.isClosed());

            System.out.println("命令执行完成,执行日志如下:");

            System.out.println(runLog.toString());

            System.out.println("命令执行完成,执行错误日志如下:");

            System.out.println(errLog.toString());

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            try {

                if (inputStreamReader != null) {

                    inputStreamReader.close();

                }

                if (errInputStreamReader != null) {

                    errInputStreamReader.close();

                }

 

                if (channelExec != null) {

                    channelExec.disconnect();

                }

                if (session != null) {

                    session.disconnect();

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

 

        return runLog.toString();

    }

}

上述工具类使用:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package org.example;

 

import org.example.shell.Shell;

 

/**

 * Hello world!

 *

 */

public class App {

    public static void main( String[] args ) {

        String cmd = "ls -1";

        Shell shell = new Shell("192.168.10.10", "ubuntu", "11111");

        String execLog = shell.execCommand(cmd);

        System.out.println(execLog);

    }

}

需要注意的点

如果需要后台执行某个命令,不能直接 <命令> + & 的方式执行,这样在 JSch 中不生效,需要写成这样的格式:<命令> > /dev/null 2>&1 &。比如要后台执行 sleep 60,需要写成 sleep 60 > /dev/null 2>&1

具体 issue 见这里:https://stackoverflow.com/questions/37833683/running-programs-using-jsch-in-the-background

参考文档

https://www.cnblogs.com/slankka/p/11988477.html

https://blog.csdn.net/sinat_24928447/article/details/83022818


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/qianghaohao/article/details/115281105
相关文章
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • Java中的字节码增强技术

    Java中的字节码增强技术
    1.字节码增强技术 字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。 参考地址 2.常见技术 技术分类 类
  • Redis BloomFilter布隆过滤器原理与实现

    Redis BloomFilter布隆过滤器原理与实现
    Bloom Filter 概念 布隆过滤器(英语:Bloom Filter)是1970年由一个叫布隆的小伙子提出的。它实际上是一个很长的二进制向量和一系列随机映射
  • Java C++算法题解leetcode801使序列递增的最小交换次

    Java C++算法题解leetcode801使序列递增的最小交换次
    题目要求 思路:状态机DP 实现一:状态机 Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int minSwap(int[] nums1, int[] nums2) { int n
  • Mybatis结果集映射与生命周期介绍

    Mybatis结果集映射与生命周期介绍
    一、ResultMap结果集映射 1、设计思想 对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了 2、resultMap的应用场
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计