Я пытаюсь запустить команду над SSH с помощью JSch, но у JSch практически нет документации, и примеры, которые я нашел, ужасны. Например, this one не показывает код для обработки выходного потока. И this one использует уродливый взлом, чтобы узнать, когда прекратить чтение из выходного потока.Запустить команду над SSH с помощью JSch
ответ
Следующий пример кода, написанный на Java, позволит вам выполнить любую команду на внешнем компьютере через SSH из java-программы. Вам нужно будет добавить файл jar.jcraft.jsch.
/*
* SSHManager
*
* @author cabbott
* @version 1.0
*/
package cabbott.net;
import com.jcraft.jsch.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SSHManager
{
private static final Logger LOGGER =
Logger.getLogger(SSHManager.class.getName());
private JSch jschSSHChannel;
private String strUserName;
private String strConnectionIP;
private int intConnectionPort;
private String strPassword;
private Session sesConnection;
private int intTimeOut;
private void doCommonConstructorActions(String userName,
String password, String connectionIP, String knownHostsFileName)
{
jschSSHChannel = new JSch();
try
{
jschSSHChannel.setKnownHosts(knownHostsFileName);
}
catch(JSchException jschX)
{
logError(jschX.getMessage());
}
strUserName = userName;
strPassword = password;
strConnectionIP = connectionIP;
}
public SSHManager(String userName, String password,
String connectionIP, String knownHostsFileName)
{
doCommonConstructorActions(userName, password,
connectionIP, knownHostsFileName);
intConnectionPort = 22;
intTimeOut = 60000;
}
public SSHManager(String userName, String password, String connectionIP,
String knownHostsFileName, int connectionPort)
{
doCommonConstructorActions(userName, password, connectionIP,
knownHostsFileName);
intConnectionPort = connectionPort;
intTimeOut = 60000;
}
public SSHManager(String userName, String password, String connectionIP,
String knownHostsFileName, int connectionPort, int timeOutMilliseconds)
{
doCommonConstructorActions(userName, password, connectionIP,
knownHostsFileName);
intConnectionPort = connectionPort;
intTimeOut = timeOutMilliseconds;
}
public String connect()
{
String errorMessage = null;
try
{
sesConnection = jschSSHChannel.getSession(strUserName,
strConnectionIP, intConnectionPort);
sesConnection.setPassword(strPassword);
// UNCOMMENT THIS FOR TESTING PURPOSES, BUT DO NOT USE IN PRODUCTION
// sesConnection.setConfig("StrictHostKeyChecking", "no");
sesConnection.connect(intTimeOut);
}
catch(JSchException jschX)
{
errorMessage = jschX.getMessage();
}
return errorMessage;
}
private String logError(String errorMessage)
{
if(errorMessage != null)
{
LOGGER.log(Level.SEVERE, "{0}:{1} - {2}",
new Object[]{strConnectionIP, intConnectionPort, errorMessage});
}
return errorMessage;
}
private String logWarning(String warnMessage)
{
if(warnMessage != null)
{
LOGGER.log(Level.WARNING, "{0}:{1} - {2}",
new Object[]{strConnectionIP, intConnectionPort, warnMessage});
}
return warnMessage;
}
public String sendCommand(String command)
{
StringBuilder outputBuffer = new StringBuilder();
try
{
Channel channel = sesConnection.openChannel("exec");
((ChannelExec)channel).setCommand(command);
InputStream commandOutput = channel.getInputStream();
channel.connect();
int readByte = commandOutput.read();
while(readByte != 0xffffffff)
{
outputBuffer.append((char)readByte);
readByte = commandOutput.read();
}
channel.disconnect();
}
catch(IOException ioX)
{
logWarning(ioX.getMessage());
return null;
}
catch(JSchException jschX)
{
logWarning(jschX.getMessage());
return null;
}
return outputBuffer.toString();
}
public void close()
{
sesConnection.disconnect();
}
}
Для тестирования.
/**
* Test of sendCommand method, of class SSHManager.
*/
@Test
public void testSendCommand()
{
System.out.println("sendCommand");
/**
* YOU MUST CHANGE THE FOLLOWING
* FILE_NAME: A FILE IN THE DIRECTORY
* USER: LOGIN USER NAME
* PASSWORD: PASSWORD FOR THAT USER
* HOST: IP ADDRESS OF THE SSH SERVER
**/
String command = "ls FILE_NAME";
String userName = "USER";
String password = "PASSWORD";
String connectionIP = "HOST";
SSHManager instance = new SSHManager(userName, password, connectionIP, "");
String errorMessage = instance.connect();
if(errorMessage != null)
{
System.out.println(errorMessage);
fail();
}
String expResult = "FILE_NAME\n";
// call sendCommand for each command and the output
//(without prompts) is returned
String result = instance.sendCommand(command);
// close only after all commands are sent
instance.close();
assertEquals(expResult, result);
}
Терминал gritty был написан для использования Jsch, но с лучшей обработкой и эмуляцией vt102. Вы можете посмотреть код там. Мы используем его, и он работает отлично.
Это бесстыдный плагин, но я сейчас writing несколько обширных Javadoc for JSch.
Также есть Manual в JSch Wiki (написано в основном мной).
О первоначальном вопросе, на самом деле нет примера для обработки потоков. Чтение/запись потока выполняется, как всегда.
Но просто не может быть уверенного способа узнать, когда одна команда в оболочке завершилась только после чтения вывода оболочки (это не зависит от протокола SSH).
Если оболочка является интерактивной, то есть имеет терминал, она обычно печатает приглашение, которое вы можете попытаться распознать. Но, по крайней мере, теоретически эта строка подсказок также может возникать при нормальном выходе из команды. Если вы хотите быть уверенным, откройте отдельные каналы exec
для каждой команды вместо использования канала оболочки. Я думаю, что канал оболочки в основном используется для интерактивного использования человеком.
Я боролся за полдня, чтобы заставить АОХ работать без использования System.in, поскольку входной поток бесполезен. Я попробовал Ganymed http://www.ganymed.ethz.ch/ssh2/ и сделал это через 5 минут. Все примеры, похоже, направлены на одно использование приложения, и ни один из примеров не показал, что мне нужно. Пример Ганимеда Basic.java Baaaboof Имеет все, что мне нужно.
Я использую АОН с 2000 года и все еще нахожу его хорошей библиотекой для использования. Я согласен, что это недостаточно хорошо документировано, но предоставленные примеры кажутся достаточно хорошими, чтобы понять, что требуется в течение нескольких минут, а удобный Swing, хотя это довольно оригинальный подход, позволяет быстро протестировать пример, чтобы убедиться, что он действительно работает. Не всегда верно, что каждый хороший проект требует в три раза больше документации, чем количество написанного кода, и даже когда это присутствует, это не всегда помогает быстрее писать рабочий прототип вашей концепции.
Если вы ищете документации JSCH..this может помочь вам: http://epaul.github.io/jsch-documentation/javadoc/com/jcraft/jsch/Session.html –
Использование:
String remoteCommandOutput = exec("ssh://user:[email protected]/work/dir/path", "ls -t | head -n1");
String remoteShellOutput = shell("ssh://user:[email protected]/work/dir/path", "ls");
shell("ssh://user:[email protected]/work/dir/path", "ls", System.out);
shell("ssh://user:[email protected]", System.in, System.out);
sftp("file:/C:/home/file.txt", "ssh://user:[email protected]/home");
sftp("ssh://user:[email protected]/home/file.txt", "file:/C:/home");
Реализация:
import static com.google.common.base.Preconditions.checkState;
import static java.lang.Thread.sleep;
import static org.apache.commons.io.FilenameUtils.getFullPath;
import static org.apache.commons.io.FilenameUtils.getName;
import static org.apache.commons.lang3.StringUtils.trim;
import com.google.common.collect.ImmutableMap;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
public final class SshUtils {
private static final Logger LOG = LoggerFactory.getLogger(SshUtils.class);
private static final String SSH = "ssh";
private static final String FILE = "file";
private SshUtils() {
}
/**
* <pre>
* <code>
* sftp("file:/C:/home/file.txt", "ssh://user:[email protected]/home");
* sftp("ssh://user:[email protected]/home/file.txt", "file:/C:/home");
* </code>
*
* <pre>
*
* @param fromUri
* file
* @param toUri
* directory
*/
public static void sftp(String fromUri, String toUri) {
URI from = URI.create(fromUri);
URI to = URI.create(toUri);
if (SSH.equals(to.getScheme()) && FILE.equals(from.getScheme()))
upload(from, to);
else if (SSH.equals(from.getScheme()) && FILE.equals(to.getScheme()))
download(from, to);
else
throw new IllegalArgumentException();
}
private static void upload(URI from, URI to) {
try (SessionHolder<ChannelSftp> session = new SessionHolder<>("sftp", to);
FileInputStream fis = new FileInputStream(new File(from))) {
LOG.info("Uploading {} --> {}", from, session.getMaskedUri());
ChannelSftp channel = session.getChannel();
channel.connect();
channel.cd(to.getPath());
channel.put(fis, getName(from.getPath()));
} catch (Exception e) {
throw new RuntimeException("Cannot upload file", e);
}
}
private static void download(URI from, URI to) {
File out = new File(new File(to), getName(from.getPath()));
try (SessionHolder<ChannelSftp> session = new SessionHolder<>("sftp", from);
OutputStream os = new FileOutputStream(out);
BufferedOutputStream bos = new BufferedOutputStream(os)) {
LOG.info("Downloading {} --> {}", session.getMaskedUri(), to);
ChannelSftp channel = session.getChannel();
channel.connect();
channel.cd(getFullPath(from.getPath()));
channel.get(getName(from.getPath()), bos);
} catch (Exception e) {
throw new RuntimeException("Cannot download file", e);
}
}
/**
* <pre>
* <code>
* shell("ssh://user:[email protected]", System.in, System.out);
* </code>
* </pre>
*/
public static void shell(String connectUri, InputStream is, OutputStream os) {
try (SessionHolder<ChannelShell> session = new SessionHolder<>("shell", URI.create(connectUri))) {
shell(session, is, os);
}
}
/**
* <pre>
* <code>
* String remoteOutput = shell("ssh://user:[email protected]/work/dir/path", "ls")
* </code>
* </pre>
*/
public static String shell(String connectUri, String command) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
shell(connectUri, command, baos);
return baos.toString();
} catch (RuntimeException e) {
LOG.warn(baos.toString());
throw e;
}
}
/**
* <pre>
* <code>
* shell("ssh://user:[email protected]/work/dir/path", "ls", System.out)
* </code>
* </pre>
*/
public static void shell(String connectUri, String script, OutputStream out) {
try (SessionHolder<ChannelShell> session = new SessionHolder<>("shell", URI.create(connectUri));
PipedOutputStream pipe = new PipedOutputStream();
PipedInputStream in = new PipedInputStream(pipe);
PrintWriter pw = new PrintWriter(pipe)) {
if (session.getWorkDir() != null)
pw.println("cd " + session.getWorkDir());
pw.println(script);
pw.println("exit");
pw.flush();
shell(session, in, out);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void shell(SessionHolder<ChannelShell> session, InputStream is, OutputStream os) {
try {
ChannelShell channel = session.getChannel();
channel.setInputStream(is, true);
channel.setOutputStream(os, true);
LOG.info("Starting shell for " + session.getMaskedUri());
session.execute();
session.assertExitStatus("Check shell output for error details.");
} catch (InterruptedException | JSchException e) {
throw new RuntimeException("Cannot execute script", e);
}
}
/**
* <pre>
* <code>
* System.out.println(exec("ssh://user:[email protected]/work/dir/path", "ls -t | head -n1"));
* </code>
*
* <pre>
*
* @param connectUri
* @param command
* @return
*/
public static String exec(String connectUri, String command) {
try (SessionHolder<ChannelExec> session = new SessionHolder<>("exec", URI.create(connectUri))) {
String scriptToExecute = session.getWorkDir() == null
? command
: "cd " + session.getWorkDir() + "\n" + command;
return exec(session, scriptToExecute);
}
}
private static String exec(SessionHolder<ChannelExec> session, String command) {
try (PipedOutputStream errPipe = new PipedOutputStream();
PipedInputStream errIs = new PipedInputStream(errPipe);
InputStream is = session.getChannel().getInputStream()) {
ChannelExec channel = session.getChannel();
channel.setInputStream(null);
channel.setErrStream(errPipe);
channel.setCommand(command);
LOG.info("Starting exec for " + session.getMaskedUri());
session.execute();
String output = IOUtils.toString(is);
session.assertExitStatus(IOUtils.toString(errIs));
return trim(output);
} catch (InterruptedException | JSchException | IOException e) {
throw new RuntimeException("Cannot execute command", e);
}
}
public static class SessionHolder<C extends Channel> implements Closeable {
private static final int DEFAULT_CONNECT_TIMEOUT = 5000;
private static final int DEFAULT_PORT = 22;
private static final int TERMINAL_HEIGHT = 1000;
private static final int TERMINAL_WIDTH = 1000;
private static final int TERMINAL_WIDTH_IN_PIXELS = 1000;
private static final int TERMINAL_HEIGHT_IN_PIXELS = 1000;
private static final int DEFAULT_WAIT_TIMEOUT = 100;
private String channelType;
private URI uri;
private Session session;
private C channel;
public SessionHolder(String channelType, URI uri) {
this(channelType, uri, ImmutableMap.of("StrictHostKeyChecking", "no"));
}
public SessionHolder(String channelType, URI uri, Map<String, String> props) {
this.channelType = channelType;
this.uri = uri;
this.session = newSession(props);
this.channel = newChannel(session);
}
private Session newSession(Map<String, String> props) {
try {
Properties config = new Properties();
config.putAll(props);
JSch jsch = new JSch();
Session newSession = jsch.getSession(getUser(), uri.getHost(), getPort());
newSession.setPassword(getPass());
newSession.setUserInfo(new User(getUser(), getPass()));
newSession.setDaemonThread(true);
newSession.setConfig(config);
newSession.connect(DEFAULT_CONNECT_TIMEOUT);
return newSession;
} catch (JSchException e) {
throw new RuntimeException("Cannot create session for " + getMaskedUri(), e);
}
}
@SuppressWarnings("unchecked")
private C newChannel(Session session) {
try {
Channel newChannel = session.openChannel(channelType);
if (newChannel instanceof ChannelShell) {
ChannelShell channelShell = (ChannelShell) newChannel;
channelShell.setPtyType("ANSI", TERMINAL_WIDTH, TERMINAL_HEIGHT, TERMINAL_WIDTH_IN_PIXELS, TERMINAL_HEIGHT_IN_PIXELS);
}
return (C) newChannel;
} catch (JSchException e) {
throw new RuntimeException("Cannot create " + channelType + " channel for " + getMaskedUri(), e);
}
}
public void assertExitStatus(String failMessage) {
checkState(channel.getExitStatus() == 0, "Exit status %s for %s\n%s", channel.getExitStatus(), getMaskedUri(), failMessage);
}
public void execute() throws JSchException, InterruptedException {
channel.connect();
channel.start();
while (!channel.isEOF())
sleep(DEFAULT_WAIT_TIMEOUT);
}
public Session getSession() {
return session;
}
public C getChannel() {
return channel;
}
@Override
public void close() {
if (channel != null)
channel.disconnect();
if (session != null)
session.disconnect();
}
public String getMaskedUri() {
return uri.toString().replaceFirst(":[^:]*[email protected]", "@");
}
public int getPort() {
return uri.getPort() < 0 ? DEFAULT_PORT : uri.getPort();
}
public String getUser() {
return uri.getUserInfo().split(":")[0];
}
public String getPass() {
return uri.getUserInfo().split(":")[1];
}
public String getWorkDir() {
return uri.getPath();
}
}
private static class User implements UserInfo, UIKeyboardInteractive {
private String user;
private String pass;
public User(String user, String pass) {
this.user = user;
this.pass = pass;
}
@Override
public String getPassword() {
return pass;
}
@Override
public boolean promptYesNo(String str) {
return false;
}
@Override
public String getPassphrase() {
return user;
}
@Override
public boolean promptPassphrase(String message) {
return true;
}
@Override
public boolean promptPassword(String message) {
return true;
}
@Override
public void showMessage(String message) {
// do nothing
}
@Override
public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
return null;
}
}
}
Обратите внимание, что ответ Милосердие Лещинский может быть немного вопрос, когда есть некоторая задержка в ответе. например:
lparstat 1 5 возвращается одна строка и работ ответ,
lparstat 5 1 должен вернуть 5 строк, но только возвращает первый
Я поставил вывод команды в то время как в другой ... Я уверен, что есть лучший способ, я должен был сделать это как быстро исправить
while (commandOutput.available() > 0) {
while (readByte != 0xffffffff) {
outputBuffer.append((char) readByte);
readByte = commandOutput.read();
}
try {Thread.sleep(1000);} catch (Exception ee) {}
}
- 1. Невозможно запустить верхнюю команду с помощью jsch
- 2. Невозможно выполнить команду в SSH с JSch
- 3. JSch: Запустить команду после того, как SSH многоуровневого
- 4. Использование корневых команд с помощью JSch (ssh)
- 5. Jsch addidentity с помощью Android
- 6. Как запустить команду «композитор» через SSH?
- 7. Как запустить команду ssh en впоследствии локальную команду в скрипте?
- 8. Мой сеанс JSch не выполняет команду
- 9. Как запустить и отобразить результат команды оболочки ssh с помощью JSch?
- 10. Как правильно запустить команду «сверху» через SSH?
- 11. Запустить команду SSH для потока журналов Rails
- 12. Алиас запустить команду сразу после SSH
- 13. Запустить команду ssh forwarding перед командой nagios
- 14. Запустить ssh и немедленно выполнить команду
- 15. запустить файл задания через команду ssh, как?
- 16. Java - ssh-tunneling to mysqldatabase с JSch
- 17. Jsch - Передача команд через ssh
- 18. Выполнение команд ssh одним в оболочке с использованием jsch ssh
- 19. Как пройти в пароле в УПП с помощью Java SSH JSch и jcabi-SSH
- 20. как запустить команду ubuntu с правами root с помощью phpseclib
- 21. Sublime text 2 - Как запустить команду оболочки поверх ssh?
- 22. Создание SSH туннеля, не выполнив команду SSH
- 23. Выполнение команд над ssh с помощью Java
- 24. Несколько каналов SHELL JSch java SSH
- 25. как запустить команду в ssh-keygen.exe с java
- 26. JSCH SSH дает мне постоянный аут err
- 27. Выполнение команды здесь-ДОК с помощью JSch
- 28. Как запустить команду на удаленной машине с помощью perl?
- 29. Как запустить SSH-команды с помощью Net :: SSH :: Perl?
- 30. JSch аутентифицировать пользователя на сервере SSH
'InputStream commandOutput' явно не закрывается явно. Будет ли она создавать какие-либо утечки? – stanleyxu2005
@ stanleyxu2005 http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#close%28%29 Закрытый метод InputStream ничего не делает. –
Мне жаль, что я не могу дать больше очков для вашего ответа. – solti