Java使用jsch和expect4j执行Linux命令

1.背景

    最近项目上需要远程链接至Linxu服务器执行语句,所以自己研究了下,找到了几个开源框架,并且稍微封装了一个Util类,供大家参考。

2.准备工作

    Pom文件引入依赖

​<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.54</version>
</dependency>
<dependency>
    <groupId>com.github.cverges</groupId>
    <artifactId>expect4j</artifactId>
    <version>1.9</version>
</dependency>

3.工具类分享

import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import expect4j.Expect4j;
import expect4j.matches.EofMatch;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;
import expect4j.matches.TimeoutMatch;
import org.apache.oro.text.regex.MalformedPatternException;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

/**
 * 执行shell语句工具类
 */
@Component
public class CMDUtilShell {
    private static final int COMMAND_EXECUTION_SUCCESS_OPCODE = -2;
    private static final String BACKSLASH_R = "\r";

    /**
     * 执行配置命令
     * @param commands 要执行的命令,为字符数组
     * @return 执行是否成功
     */
    public String executeCommands(String[] commands, String ip, int port, String user, String password, Integer sshTimeout) {
        Session session = null;
        ChannelShell channel = null;
        Expect4j expect = null;

        try {
            session = new JSch().getSession(user, ip, port);
            session.setPassword(password);
            session.setConfig(bulidConfig());
            // 设置不提示输入密码、不显示登入信息等
            session.setUserInfo(new LocalUserInfo());
            session.connect();
            channel = (ChannelShell) session.openChannel("shell");
            expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
            channel.connect(sshTimeout + 1000);

            // 存放返回值
            StringBuffer buffer = new StringBuffer();
            // 执行语句
            List<Match> lstPattern = bulidPattern(buffer, sshTimeout);

            for (String strCmd : commands) {
                if (expect.expect(lstPattern) != COMMAND_EXECUTION_SUCCESS_OPCODE) {
                    expect.send(strCmd);
                    expect.send(BACKSLASH_R);
                }
            }
            expect.expect(lstPattern);
            return buffer.toString().toLowerCase();

        } catch (Exception ex) {
            String errorMsg = String.format("[@CMDUtilShell] host=[%s] user=[%s] [error=%s]", ip, user, ex.getMessage());
        } finally {
            if (expect != null) {
                expect.close();
            }
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
    }

    /**
     * 构建配置项
     */
    private Hashtable<String, String> bulidConfig() {
        Hashtable<String, String> config = new Hashtable<>();
        config.put("userauth.gssapi-with-mic", "no");
        config.put("StrictHostKeyChecking", "no");
        return config;
    }

    /**
     * 构建模式
     */
    private List<Match> bulidPattern(StringBuffer buffer, Integer sshTimeout) throws MalformedPatternException {
        List<Match> lstPattern = new ArrayList<>();
        // 终止符
        // todo:存入数据库使用参数配置
        String[] regEx = {"~]#", "~#", ":~#",};
        for (String regexElement : regEx) {
            RegExpMatch mat = new RegExpMatch(regexElement, x -> {
                buffer.append(x.getBuffer());
            });
            lstPattern.add(mat);
        }

        lstPattern.add(new EofMatch(x -> {
        }));

        // 设置超时时间
        lstPattern.add(new TimeoutMatch(sshTimeout, x -> {
        }));

        return lstPattern;
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
昨天一个网友问如何能够将输入密码的工作在shell里面自动完成,研究了一下,发现这种交互式的工作,普通的shell实现不了,据说可以借助expect来搞定,所以初步学习了一下expect,成果和大家分享一下: 应用一: 实现从普通用户“test”切换到root用户,自动输入root的密码,不用在终端提示符下执行密码输入操作。 步骤: (1)vi autosu.sh (2)#! /usr/bin/expect -f //指定expect工具的路径,如果不清楚具体路径,可以用"which expect"命令来查看。 spawn su - // 在expect 中用"spawn"关键字来调用命令“su - ” expect ":" //在执行了su - 命令之后,提示输入密码的提示符。例如你在执行了su - 命令之后,终端里面会出现提示“口令:”,那么你就可以在这里写expect ":",或者expect -exact "口令:" send "rootpasswd\r" //这里expect用send将你的root密码自动输入到上面的提示符之后。 interact //操作完成。 注意:这里强调一下执行脚本时要注意的地方,不能按照习惯来用sh ***.sh来这行expect的程序,会提示找不到命令,因为expect用的不是bash所以会报错。执行的时候直接./***.sh就可以了。~切记! 应用二: 从普通用户切换到root之后,执行“ls”操作,调用执行aaa.sh,返回执行结果,间隔10S。 #/usr/bin/expect -f spawn su - // 在expect 中用"spawn"关键字来调用命令“su - ” expect ":" //在执行了su - 命令之后,提示输入密码的提示符。例如你在执行了su - 命令之后,终端里面会出现提示“口令:”,那么你就可以在这里写expect ":",或者expect -exact "口令:" send "rootpasswd\r" //这里expect用send将你的root密码自动输入到上面的提示符之后。 expect "#" //当遇到提示符以#结尾时,即为root权限时; send "ls\r" //expect 用spend方法调用ls 命令,并且回车(“\r”) expect "#" send "sh aaa.sh\r" //调用sh aaa.sh,即执行一个脚本文件aaa.sh。 expect "#" send "echo $?\r" sleep 10 interact
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值