Java远程执行Shell指令

        JSch(Java Secure Channel)是SSH2的一个纯Java实现。它允许你连接到一个sshd 服务器,进而使用端口转发,X11转发,文件传输等等功能。在前面的博客里,有介绍到如何使用JSch实现SFTP的相关操作,本文这里主要介绍如何利用JSch进行远程Shell操作。

软硬件环境说明Windows10、IntelliJ IDEA、SpringBoot 2.1.4.RELEASE、CentOS7。

准备工作:在pom.xml中引入JSch依赖

<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

编写执行Shell指令的工具类

import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

/**
 * 执行Shell工具类
 *
 * @author JustryDeng
 * @date 2019/4/29 16:29
 */
public class ExecuteShellUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExecuteShellUtil.class);

    /** 未调用初始化方法 错误提示信息 */
    private static final String DONOT_INIT_ERROR_MSG = "please invoke init(...) first!";

    private Session session;

    private Channel channel;

    private ChannelExec channelExec;

    private ExecuteShellUtil() {
    }

    /**
     * 获取ExecuteShellUtil类实例对象
     *
     * @return 实例
     * @date 2019/4/29 16:58
     */
    public static ExecuteShellUtil getInstance() {
        return new ExecuteShellUtil();
    }

    /**
     * 初始化
     *
     * @param ip
     *         远程Linux地址
     * @param port
     *         端口
     * @param username
     *         用户名
     * @param password
     *         密码
     * @throws JSchException
     *         JSch异常
     * @date 2019/3/15 12:41
     */
    public void init(String ip, Integer port, String username, String password) throws JSchException {
        JSch jsch = new JSch();
        jsch.getSession(username, ip, port);
        session = jsch.getSession(username, ip, port);
        session.setPassword(password);
        Properties sshConfig = new Properties();
        sshConfig.put("StrictHostKeyChecking", "no");
        session.setConfig(sshConfig);
        session.connect(60 * 1000);
        LOGGER.info("Session connected!");
        // 打开执行shell指令的通道
        channel = session.openChannel("exec");
        channelExec = (ChannelExec) channel;
    }

    /**
     * 执行一条命令
     */
    public String execCmd(String command) throws Exception {
        if (session == null || channel == null || channelExec == null) {
            throw new Exception(DONOT_INIT_ERROR_MSG);
        }
        LOGGER.info("execCmd command - > {}", command);
        channelExec.setCommand(command);
        channel.setInputStream(null);
        channelExec.setErrStream(System.err);
        channel.connect();
        StringBuilder sb = new StringBuilder(16);
        try (InputStream in = channelExec.getInputStream();
             InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
             BufferedReader reader = new BufferedReader(isr)) {
            String buffer;
            while ((buffer = reader.readLine()) != null) {
                sb.append("\n").append(buffer);
            }
            // 释放资源
            close();
            LOGGER.info("execCmd result - > {}", sb);
            return sb.toString();
        }
    }

    /**
     * 释放资源
     *
     * @date 2019/3/15 12:47
     */
    private void close() {
        if (channelExec != null && channelExec.isConnected()) {
            channelExec.disconnect();
        }
        if (channel != null && channel.isConnected()) {
            channel.disconnect();
        }
        if (session != null && session.isConnected()) {
            session.disconnect();
        }
    }

}

测试一下

测试一:

控制台输出:

测试二:

控制台输出:

由此可见,远程执行shell指令的工具类编写成功!

注:不仅能执行上面示例的shell,还能执行cp、mv等等等等指令,这里就不再一一示例了。

注:如果要执行多个指令,可以多次调用工具类,也可以像使用多指令shell一样,使用【;】或【&&】等符
       号将多个指令隔开

        追注:1、【;】隔开的多个shell命令,会按照顺序执行下来,但是不能保证每条命令都执行成功。
                   2、【&&】隔开的多个shell命令,前面的命令执行成功,才会执行后面的命令,否则后面的命令
                           不执行。
                   3、将多指令隔开的符号,上面给出的只是最常用的两种,更多功能的符号可自行查阅相关资料。
         如:

 

^_^ 如有不当之处,欢迎指正

^_^ 本文已被收录进《程序员成长笔记(五)》,笔者JustryDeng

### 调用Ansible Playbook 为了从Java程序中远程执行Ansible Playbook,可以采用多种方法。一种常见的方式是利用Java进程API来启动外部命令,即`ansible-playbook`命令。这允许Java应用程序触发Playbook的执行。 #### 方法一:使用ProcessBuilder类 下面是一个简单的例子展示如何通过Java中的`ProcessBuilder`类来调用Ansible Playbook: ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class AnsibleExecutor { public static void main(String[] args) throws Exception { ProcessBuilder pb = new ProcessBuilder("ansible-playbook", "playbook.yml"); pb.redirectErrorStream(true); Process p = pb.start(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } int exitCode = p.waitFor(); System.out.println("\nExited with error code : " + exitCode); } } ``` 这段代码创建了一个新的子过程来执行指定的命令,并读取其标准输出流的内容直到结束[^1]。 #### 方法二:借助Jsch库SSH方式 另一种更灵活的方法是使用JSch库来进行SSH连接,从而可以在不同的服务器上运行Ansible Playbooks而不需要直接在同一台机器上调用它们。这种方式特别适合于跨网络环境下的自动化操作场景。 首先需要引入Maven依赖项(如果项目基于Maven构建的话): ```xml <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency> ``` 接着编写如下所示的Java代码片段用于建立SSH会话并通过该通道发送指令给远端主机上的shell解释器处理: ```java import com.jcraft.jsch.*; public class RemoteAnsibleRunner { private final JSch jsch = new JSch(); public Session connect(String host, String user, String privateKeyPath) throws JSchException { Session session = jsch.getSession(user, host, 22); jsch.addIdentity(privateKeyPath); // 添加私钥文件路径 java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); return session; } public void runRemoteCommand(Session session, String command) throws JSchException { Channel channel=session.openChannel("exec"); ((ChannelExec)channel).setCommand(command); channel.setInputStream(null); ((ChannelExec)channel).setErrStream(System.err); InputStream in=channel.getInputStream(); channel.connect(); byte[] tmp=new byte[1024]; while(true){ while(in.available()>0){ int i=in.read(tmp, 0, 1024); if(i<0)break; System.out.print(new String(tmp, 0, i)); } if(channel.isClosed()){ break; } Thread.sleep(1000); } channel.disconnect(); } public static void main(String[] args)throws Exception{ RemoteAnsibleRunner runner = new RemoteAnsibleRunner(); Session session = runner.connect("your_remote_host","username","/path/to/private/key"); runner.runRemoteCommand(session,"ansible-playbook /full/path/on/server/playbook.yml"); session.disconnect(); } } ``` 此段代码展示了怎样设置一个安全壳协议(Secure Shell Protocol),并以此为基础向目标计算机发出执行特定Ansible Playbook请求的操作[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值