tutorial jcraft from example descargar java ssh jsch

java - jcraft - Ejecute un comando sobre SSH con JSch



maven jcraft jsch (8)

Estoy intentando ejecutar un comando sobre SSH con JSch, pero JSch prácticamente no tiene documentación y los ejemplos que he encontrado son terribles. Por ejemplo, este no muestra código para manejar el flujo de salida. Y, este utiliza un hack feo para saber cuándo dejar de leer desde la secuencia de salida.


Este es un complemento descarado, pero ahora estoy writing un extenso Javadoc para JSch .

Además, ahora hay un Manual en JSch Wiki (escrito principalmente por mí).

Acerca de la pregunta original, no hay realmente un ejemplo para manejar las transmisiones. Leer / escribir una transmisión se hace como siempre.

Pero simplemente no puede haber una manera segura de saber cuándo un comando en un shell ha terminado simplemente leyendo el resultado del shell (esto es independiente del protocolo SSH).

Si el intérprete de comandos es interactivo, es decir, tiene un terminal conectado, generalmente imprimirá un mensaje que usted podría tratar de reconocer. Pero al menos teóricamente, esta cadena de aviso también podría producirse en la salida normal de un comando. Si quiere estar seguro, abra canales de exec individuales para cada comando en lugar de usar un canal de shell. El canal de shell se usa principalmente para uso interactivo por un usuario humano, creo.


Estoy usando JSCH desde aproximadamente 2000 y todavía lo encuentro una buena biblioteca para usar. Estoy de acuerdo en que no está suficientemente documentado pero los ejemplos proporcionados parecen lo suficientemente buenos como para entender que es necesario en varios minutos, y Swing, que es fácil de usar, aunque es un enfoque bastante original, permite probar el ejemplo rápidamente para asegurarse de que realmente funciona. No siempre es verdad que cada buen proyecto necesita tres veces más documentación que la cantidad de código escrito, e incluso cuando está presente, esto no siempre ayuda a escribir más rápido un prototipo funcional de su concepto.


La terminal gritty fue escrita para usar Jsch, pero con un mejor manejo y emulación vt102. Puedes echarle un vistazo al código allí. Lo usamos y funciona bien.


Luché durante medio día para hacer que JSCH funcione sin utilizar System.in como flujo de entrada en vano. Probé Ganymed http://www.ganymed.ethz.ch/ssh2/ y lo tuve en 5 minutos. Todos los ejemplos parecen estar dirigidos a un uso de la aplicación y ninguno de los ejemplos mostró lo que necesitaba. El ejemplo de Ganymed Basic.java Baaaboof tiene todo lo que necesito.


Tenga en cuenta que la respuesta de Charity Leschinski puede tener un pequeño problema cuando hay algún retraso en la respuesta. p.ej:
lparstat 1 5 devuelve una línea de respuesta y funciona,
lparstat 5 1 debería devolver 5 líneas, pero solo devuelve la primera

He puesto el comando de salida mientras estaba dentro de otro ... Estoy seguro de que hay una mejor manera, tuve que hacer esto como una solución rápida

while (commandOutput.available() > 0) { while (readByte != 0xffffffff) { outputBuffer.append((char) readByte); readByte = commandOutput.read(); } try {Thread.sleep(1000);} catch (Exception ee) {} }


Uso:

String remoteCommandOutput = exec("ssh://user:pass@host/work/dir/path", "ls -t | head -n1"); String remoteShellOutput = shell("ssh://user:pass@host/work/dir/path", "ls"); shell("ssh://user:pass@host/work/dir/path", "ls", System.out); shell("ssh://user:pass@host", System.in, System.out); sftp("file:/C:/home/file.txt", "ssh://user:pass@host/home"); sftp("ssh://user:pass@host/home/file.txt", "file:/C:/home");

Implementación:

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:pass@host/home"); * sftp("ssh://user:pass@host/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:pass@host", 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:pass@host/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:pass@host/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:pass@host/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(":[^:]*?@", "@"); } 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; } } }


usar ssh de java no debería ser tan difícil como lo hace jsch. es posible que estés mejor con sshj .


El siguiente ejemplo de código escrito en Java le permitirá ejecutar cualquier comando en una computadora extranjera a través de SSH desde un programa java. Deberá incluir el archivo jar com.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(); } }

Para las pruebas.

/** * 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); }