2011-04-29 46 views
11

Estaba intentando ejecutar varios comandos a través del protocolo SSH utilizando la biblioteca JSch. Pero parece que me he quedado estancado y no puedo encontrar ninguna solución. El método setCommand() solo puede ejecutar comandos individuales por sesión. Pero quiero ejecutar los comandos secuencialmente como la aplicación connectbot en la plataforma Android. Hasta ahora, mi código es:Múltiples comandos a través de Jsch Shell

package com.example.ssh; 

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.util.Properties; 

import android.app.Activity; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.EditText; 
import android.widget.TextView; 
import android.widget.Toast; 

import com.jcraft.jsch.Channel; 
import com.jcraft.jsch.JSch; 
import com.jcraft.jsch.JSchException; 
import com.jcraft.jsch.Session; 

public class ExampleSSH extends Activity { 
    /** Called when the activity is first created. */ 
    EditText command; 
    TextView result; 
    Session session; 
    ByteArrayOutputStream baos; 
    ByteArrayInputStream bais; 
    Channel channel; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     bais = new ByteArrayInputStream(new byte[1000]); 
     command = (EditText) findViewById(R.id.editText1); 
     result = (TextView) findViewById(R.id.terminal); 
    } 

    public void onSSH(View v){ 
     String username = "xxxyyyzzz"; 
     String password = "aaabbbccc"; 
     String host  = "192.168.1.1"; // sample ip address 
     if(command.getText().toString() != ""){ 
      JSch jsch = new JSch(); 
      try { 
       session = jsch.getSession(username, host, 22); 
       session.setPassword(password); 

       Properties properties = new Properties(); 
       properties.put("StrictHostKeyChecking", "no"); 
       session.setConfig(properties); 
       session.connect(30000); 

       channel = session.openChannel("shell"); 
       channel.setInputStream(bais); 
       channel.setOutputStream(baos); 
       channel.connect(); 

      } catch (JSchException e) { 
       // TODO Auto-generated catch block 
       Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); 
      } 
     } 
     else{ 
      Toast.makeText(this, "Command cannot be empty !", Toast.LENGTH_LONG).show(); 
     } 
    } 

    public void onCommand(View v){ 
     try { 
      bais.read(command.getText().toString().getBytes()); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     baos = new ByteArrayOutputStream(); 
     channel.setOutputStream(baos); 
     result.setText(baos.toString()); 

    } 
} 

El código parece conectarse con el servidor, pero creo que hay algún problema con los buffers de entrada y de salida de la matriz, porque no hay salida en absoluto. ¿Puede alguien guiarme por favor cómo manejar la entrada y la salida hacia y desde el servidor correctamente para obtener la salida deseada?

Respuesta

12

El comando es un String y puede ser cualquier cosa que el shell remoto acepte. Pruebe

cmd1 ; cmd2 ; cmd3 

para ejecutar varios comandos en secuencia. O

cmd1 && cmd2 && cmd3 

para ejecutar comandos hasta que uno falla.

Incluso esto podría funcionar:

cmd1 
cmd2 
cmd3 

o en Java:

channel.setCommand("cmd1\ncmd2\ncmd3"); 

Nota al margen: No ponga las contraseñas y nombres de usuario en el código. Póngalos en un archivo de propiedades y use una propiedad del sistema para especificar el nombre del archivo de propiedades. De esta forma, puede mantener el archivo incluso fuera del proyecto y asegurarse de que las contraseñas/nombres de usuario no tengan fugas.

11

Si no tiene que distinguir las entradas o salidas de los comandos individuales, la respuesta de Aaron (dando todos los comandos en una fila, separados por \n o ;) está bien.

Si tiene que manejarlos por separado, o no conoce los comandos posteriores antes de que los anteriores hayan finalizado: Puede abrir múltiples exec-Channels en la misma sesión (es decir, conexión), uno después del otro (es decir, después del antes estaba cerrado). Cada uno tiene su propio comando. (Pero no comparten el entorno, por lo que un comando cd en el primero no tiene efecto en los posteriores.)

Simplemente tiene que tener cuidado de tener el objeto Session alrededor, y no crear uno nuevo para cada mando.

Otra opción sería shell channel, y luego pasar los comandos individuales al shell remoto como entrada (es decir, a través de una transmisión). Pero luego debes tener cuidado de no mezclar la entrada de un comando con el siguiente comando (es decir, esto funciona solo si sabes lo que están haciendo los comandos, o si tienes un usuario interactivo que puede proporcionar ambas entradas al comando y el próximo comando, y sabe cuál se va a usar cuando).

+0

algún ejemplo de cómo se hace eso? – Pixie

4

Configure un objeto SCPInfo para guardar el nombre de usuario, contraseña, puerto: 22 e ip.

List<String> commands = new ArrayList<String>(); 
    commands.add("touch test1.txt"); 
    commands.add("touch test2.txt"); 
    commands.add("touch test3.txt"); 
    runCommands(scpInfo, commands); 

public static void runCommands(SCPInfo scpInfo, List<String> commands){ 
    try { 
     JSch jsch = new JSch(); 
     Session session = jsch.getSession(scpInfo.getUsername(), scpInfo.getIP(), scpInfo.getPort()); 
     session.setPassword(scpInfo.getPassword()); 
     setUpHostKey(session); 
     session.connect(); 

     Channel channel=session.openChannel("shell");//only shell 
     channel.setOutputStream(System.out); 
     PrintStream shellStream = new PrintStream(channel.getOutputStream()); // printStream for convenience 
     channel.connect(); 
     for(String command: commands) { 
      shellStream.println(command); 
      shellStream.flush(); 
     } 

     Thread.sleep(5000); 

     channel.disconnect(); 
     session.disconnect(); 
    } catch (Exception e) { 
     System.err.println("ERROR: Connecting via shell to "+scpInfo.getIP()); 
     e.printStackTrace(); 
    } 
} 

private static void setUpHostKey(Session session) { 
    // Note: There are two options to connect 
    // 1: Set StrictHostKeyChecking to no 
    // Create a Properties Object 
    // Set StrictHostKeyChecking to no 
    // session.setConfig(config); 
    // 2: Use the KnownHosts File 
    // Manually ssh into the appropriate machines via unix 
    // Go into the .ssh\known_hosts file and grab the entries for the hosts 
    // Add the entries to a known_hosts file 
    // jsch.setKnownHosts(khfile); 
    java.util.Properties config = new java.util.Properties(); 
    config.put("StrictHostKeyChecking", "no"); 
    session.setConfig(config); 
} 
+0

Esto solo funcionará si los comandos no reciben ninguna entrada, ya que de lo contrario los siguientes comandos se interpretarán como entrada al primero. –

+1

¡increíble! justo lo que estaba buscando. –

Cuestiones relacionadas