2011-04-29 838 views
11

我试图通过使用JSch库的SSH协议执行多个命令。但我似乎卡住了,找不到任何解决方案。 setCommand()方法只能在每个会话中执行单个命令。但我想按照Android平台上的connectbot应用程序的顺序执行这些命令。到目前为止,我的代码是:通过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()); 

    } 
} 

代码似乎可以连接到服务器,但我认为有一些问题,输入和输出数组缓冲区,因为有没有输出。有人可以请指导我如何妥善处理输入和输出到服务器以获得所需的输出?

回答

12

该命令是一个字符串,可以是远程shell接受的任何东西。尝试

cmd1 ; cmd2 ; cmd3 

按顺序运行几个命令。或者

cmd1 && cmd2 && cmd3 

运行命令直到一个失败。

即使这可能工作:

cmd1 
cmd2 
cmd3 

或Java中:

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

旁注:不要把密码和用户名到代码。将它们放入属性文件并使用系统属性指定属性文件的名称。这样,您可以将文件保存在项目之外,并确保密码/用户名不会泄漏。

11

如果您不需要区分单个命令的输入或输出,那么来自Aaron的回答(给出连续的所有命令,用\n;分隔)是很好的。

如果您必须单独处理它们,或者在先前的命令完成之前不知道以后的命令:您可以在同一会话(即连接)上一个接一个地打开多个exec-Channels(即在一个之后之前被关闭)。每个人都有自己的命令。 (但他们不共享的环境,所以在第一个的cd命令对后来者没有任何影响。)

您只需照顾到周围有Session对象,而不是为每个新命令。

另一种选择是shell channel,然后将各个命令作为输入(即通过流)传递给远程shell。但是,你必须注意不要将输入与下一个命令混合在一个命令中(例如,只有当你知道命令正在做什么,或者如果你有一个交互式用户可以提供输入到命令和下一个命令,并知道哪一个将被使用。)

+0

这是怎么完成的任何例子? – Pixie 2016-06-02 15:49:14

4

设置一个SCPInfo对象来保存用户名,密码,端口:22和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

这只有在命令没有输入任何输入时才会起作用,否则以下命令将被解释为第一个命令的输入。 – 2012-06-10 13:57:57

+1

太棒了!就是我在找的东西。 – 2016-11-29 16:30:25