java - 从 java 捕获 ssh 命令输出

标签 java unix ssh expect

我正在尝试从我的 java 代码运行一些 unix 命令。我目前使用的是 Google 的 Expect4J 库,并且对任何有据可查的库持开放态度。

问题是我试图捕获上次运行命令的输出,但无法获取它。有谁知道我在这里做错了什么?

我在这里试图解决的问题是连接到我的jumphost,然后通过SSH连接到其他一些服务器,根据我是否能够连接,我需要在目标服务器上复制或运行一些脚本。

下面粘贴我编写的代码。请帮忙!!!

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

import org.apache.oro.text.regex.MalformedPatternException;
import org.junit.internal.matchers.SubstringMatcher;

import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.bean.Server;

import expect4j.Closure;
import expect4j.Expect4j;
import expect4j.ExpectState;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;

public class ExpectTest1 {

    public final String RETURN_CHAR = "\r ";
    public  String expectOut = "";

    private StringBuilder sBuilder = new StringBuilder();

    /**
     * @param args
     */
    public static void main(String[] args) {
        Expect4j exp;
        List<String> cmdsToRun = new ArrayList<String>(); 

        try {
            ExpectTest1 test = new ExpectTest1();
            exp = test.SSH("jumpbox.xyz.com","user1","passwd", cmdsToRun);
            exp.getLastState().toString();
        } catch (Exception e) {
            e.printStackTrace();
    }


}

    public Expect4j SSH(String hostname, String username, String password, List<String> cmdsToRun) throws Exception {
        return SSH(hostname, username, password, 22, cmdsToRun);
    }

    public Expect4j SSH(String hostname, String username, String password, int port, List<String> cmdsToRun) throws Exception {

    JSch jsch=new JSch();
    Session session=jsch.getSession(username, hostname, port);
    if( password != null) {
        session.setPassword(password);
    }

    Hashtable config=new Hashtable();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.setDaemonThread(true);
    session.connect(3 * 1000);   // making a connection with timeout.

    ChannelShell channel = (ChannelShell) session.openChannel("shell");

    channel.setInputStream(System.in);
    channel.setOutputStream(System.out);

    channel.setPtyType("vt102");

    Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());

    channel.connect(5*1000);

    Server hostServer = new Server();
    hostServer.setHostName("box1.xyz.com");
    hostServer.setUsername("user2");

    Server destServer = new Server();
    destServer.setHostName("box2.xyz.com");
    destServer.setUsername("user3");

    boolean isLogged = doSSH(hostServer, expect);
    if(isLogged) {
        doSSH(destServer, expect);
    }

    return expect;
}

    private boolean doSSH (Server server, Expect4j expect) throws IOException, MalformedPatternException, Exception {
        String command = "ssh " + server.getUsername() + "@" + server.getHostName() + RETURN_CHAR;
        System.out.println("Logging in to: " + command);
        boolean logged;
        expect.send(command);
        Thread.sleep(4000);
        command = "uname -a" + RETURN_CHAR;
        System.out.println(command);
        expect.send(command);
        Thread.sleep(10000);

            if(isMatch(expect,server.getHostName().substring(0,server.getHostName().indexOf(".")))) {
            System.out.println("Logged in to:" + server.getHostName() + ".....");
            return true;
        }

        if(isMatch(expect, "Last login")) {
            System.out.println("Logged in to:" + server.getHostName() + ".....");
            return true;
        }

        if(isMatch(expect, "not known")) {
            System.out.println("Node or Service not known...");
            return false;
        }

        System.out.println("Node or Service not known...");
        return false;

        /*expect.expect(new Match[] {
            new RegExpMatch("Name or service not known", new Closure() {
                public void run(ExpectState state) throws Exception {
                    System.out.println("Name or service not known...");
                    expectOut = state.getBuffer();
            }
        })  
        });

        expect.expect( new Match[] {
                new RegExpMatch("Last login: \\w{3} (.*) from", new Closure() {
                    public void run(ExpectState state) throws Exception {
                        System.out.println("Logged In....");
                        expectOut = state.getBuffer();
                    }
                })
            });

        if(expectOut != null && expectOut.length()>0 && !expectOut.matches("Name or service not known")) 
            return true;

        return false;*/

    }

    private boolean isMatch(Expect4j expect, String regEx) throws MalformedPatternException, Exception {
        /*expect.expect( new Match[] {
                new RegExpMatch(regEx, new Closure() {
                    public void run(ExpectState state) throws Exception {
                        System.out.println(state.getBuffer());
                        System.out.println(state.getMatch());
                        expectOut = state.getMatch();
                        //System.out.println(state.getMatch());
                    }
                })
            });

        if(expectOut != null 
                && expectOut.length()>0 
                && expectOut.matches(regEx)) {
            //System.out.println(regEx);
            return true;
        }*/
        System.out.println("*************");
        System.out.println(expect.expect(regEx));
        System.out.println("*************");
        if(expect.expect(regEx) == 0)
            return true;

        return false;
    }

}

最佳答案

我怀疑您的 ssh 命令正在尝试提示输入密码或尝试要求您将主机 key 添加到“known_hosts”文件中。我不确定它们可以由 Expect4j 完成,因为 ssh 直接连接到 tty 来询问这些问题。但这个答案似乎已经解决了:

Using expect to pass a password to ssh

以下是可能有帮助的类似问题/答案:

How to make a ssh connection to a firewall(router) with java?

当我自动化我的 ssh 连接时,我使用公钥/私钥加密而不是密码来连接到服务器,并且我确保服务器已在没有密码的情况下从命令行成功连接到客户端。确保使用完整主机​​名。这会将主机 key 保存到“known_hosts”文件中,以便将来不会提示输入。

关于java - 从 java 捕获 ssh 命令输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8993121/

相关文章:

bash - 在 bash 'for loop' 结束时打印结果

shell - 在服务器上作为后台进程运行 java jar 文件

unix - 将输入与输出连接到 svn list 命令,然后将其传递给 grep

git - 通过 ssh 使用 git 设置 jenkins

ruby-on-rails - 来自多台 win7 64 机器的 Heroku 部署

java - HashMap的HashMap->输出问题

java - 在循环中填充 map 时,转换为 (Float) 还是声明一个新的 Float 更好?

java - 生成Javadoc以便在手机上轻松使用

java - 如何在Java中打印List对象元素?

amazon-web-services - 为 AWS Lambda 存储私有(private) SSH key 的标准做法是什么