Выполнить последовательность команд в 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;
}