【问题标题】:Capture ssh command output from java从 java 捕获 ssh 命令输出
【发布时间】:2012-02-18 01:42:05
【问题描述】:

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

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

我在这里尝试解决的问题是连接到我的跳转主机,然后通过 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;
    }

}

【问题讨论】:

    标签: java unix ssh expect


    【解决方案1】:

    只是一个想法,您可以考虑使用一个 Java 库来为您处理期望和密钥管理。这是我发现的一个似乎可以解决问题的方法。

    http://www.jscape.com/products/components/java/ssh-factory/

    有关详细信息,请参阅 SshScript 或 SshSession 类和文档。

    【讨论】:

    • 是的,Jscape 工作正常,因为我之前使用过它。唯一的问题是它是一个付费图书馆,管理层对此并不真正感兴趣(至少目前如此)。
    【解决方案2】:

    我怀疑您的 ssh 命令试图提示输入密码或试图要求您将主机密钥添加到 `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 连接时,我使用公钥/私钥加密而不是密码来连接服务器,并确保服务器已从命令行成功地从客户端连接,而无需密码。确保使用完整的主机名。这会将主机密钥保存到 `known_hosts 文件中,因此以后不会提示输入。

    【讨论】:

    • 感谢您的回答。我已经设置了从 jumphost 到 server1 以及从 server1 到 server2 的无密码条目。它实际上能够通过 SSH 连接到服务器,问题是当我传递一个不存在的服务器名称时。代码仍然识别我们已经登录到服务器了!!
    猜你喜欢
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 2021-05-29
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 2017-02-26
    相关资源
    最近更新 更多