Выполнить последовательность команд в sshj

Мне нужно выполнить некоторую последовательность команд на удаленном сервере через ssh, используя библиотеку sshj.

я делаю

        Session session = ssh.startSession();
        Session.Command cmd = session.exec("ls -l");
        System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
        cmd.join(10, TimeUnit.SECONDS);
        Session.Command cmd2 = session.exec("ls -a");
        System.out.println(IOUtils.readFully(cmd2.getInputStream()).toString());

и это бросает меня

net.schmizz.sshj.common.SSHRuntimeException: этот канал сеанса полностью израсходован

Но я не могу воссоздать сессию для каждой отдельной команды, потому что в этом примере будет показан список домашних каталогов, но не список /some/dir.

3 ответа

Решение

Вы можете рассмотреть возможность использования сторонней библиотеки, подобной Expect, которая упрощает работу с удаленными службами и сбор результатов. Эти библиотеки предназначены для выполнения последовательности команд. Вот хороший набор опций, которые вы можете попробовать:

Однако, когда я собирался решить подобную проблему, я обнаружил, что эти библиотеки довольно старые. Они также вводят много нежелательных зависимостей. Поэтому я создал свой собственный и сделал его доступным для других. Это называется ExpectIt. Преимущества моей библиотеки изложены на домашней странице проекта. Вы можете попробовать.

Вот пример взаимодействия с общедоступной удаленной службой SSH с использованием sshj:

    SSHClient ssh = new SSHClient();
    ...
    ssh.connect("sdf.org");
    ssh.authPassword("new", "");
    Session session = ssh.startSession();
    session.allocateDefaultPTY();
    Shell shell = session.startShell();
    Expect expect = new ExpectBuilder()
            .withOutput(shell.getOutputStream())
            .withInputs(shell.getInputStream(), shell.getErrorStream())
            .build();
    try {
        expect.expect(contains("[RETURN]"));
        expect.sendLine();
        String ipAddress = expect.expect(regexp("Trying (.*)\\.\\.\\.")).group(1);
        System.out.println("Captured IP: " + ipAddress);
        expect.expect(contains("login:"));
        expect.sendLine("new");
        expect.expect(contains("(Y/N)"));
        expect.send("N");
        expect.expect(regexp(": $"));
        expect.send("\b");
        expect.expect(regexp("\\(y\\/n\\)"));
        expect.sendLine("y");
        expect.expect(contains("Would you like to sign the guestbook?"));
        expect.send("n");
        expect.expect(contains("[RETURN]"));
        expect.sendLine();
    } finally {
        session.close();
        ssh.close();
        expect.close();
    }

Вот ссылка на полный работоспособный пример.

Как бы странно это ни было, session можно использовать только один раз. Таким образом, вы должны сбросить сессию каждый раз.

    Session session = ssh.startSession();
    Session.Command cmd = session.exec("ls -l");
    System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
    cmd.join(10, TimeUnit.SECONDS);

    session = ssh.startSession();
    Session.Command cmd2 = session.exec("ls -a");
    System.out.println(IOUtils.readFully(cmd2.getInputStream()).toString());

Или, если оболочка, к которой вы подключаетесь, поддерживает команды с разделителями (и ситуация это позволяет), вы можете сделать это (пример bash):

session.exec("ls -l; <command 2>; <command 3>");

Этот вопрос старый, но для пояснения, цитируя его в вики https://github.com/hierynomus/sshj/wiki

Объекты сеанса не могут использоваться повторно, поэтому вы можете иметь только одну команду / оболочку / подсистему через exec(), startShell() или startSubsystem() соответственно. Но вы можете начать несколько сеансов через одно соединение.

В нашем случае мы сделали это в функции

public String runCmd(SSHClient sshClient, String command) throws IOException  {
    String response = "";

    try (Session session = sshClient.startSession()) {
        final Command cmd = session.exec(command);
        response = (IOUtils.readFully(cmd.getInputStream()).toString());
        cmd.join(5, TimeUnit.SECONDS);
        // System.out.println("\n** exit status: " + cmd.getExitStatus());
    } 
    return response;
}
Другие вопросы по тегам