通过 JSch 外壳执行多个命令

2022-09-04 06:57:22

我试图使用JSch库通过SSH协议执行多个命令。但我似乎卡住了,找不到任何解决方案。该方法每个会话只能执行单个命令。但我想按顺序执行命令,就像Android平台上的connectbot应用程序一样。到目前为止,我的代码是:setCommand()

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());

    }
}

代码似乎连接到服务器,但我认为输入和输出数组缓冲区存在一些问题,因为根本没有输出。有人可以指导我如何正确处理服务器之间的输入和输出以获得所需的输出吗?


答案 1

该命令是一个 String,可以是远程 shell 接受的任何内容。尝试

cmd1 ; cmd2 ; cmd3

按顺序运行多个命令。或

cmd1 && cmd2 && cmd3

运行命令,直到一个命令失败。

即使这样也可能有效:

cmd1
cmd2
cmd3

或在Java中:

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

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


答案 2

如果您不必区分各个命令的输入或输出,那么Aaron的答案(以或分隔的行中给出所有命令)是可以的。\n;

如果您必须单独处理它们,或者在较早的命令完成之前不知道后面的命令:您可以在同一会话(即连接)上打开多个exec通道,一个接一个(即在之前的一个关闭之后)。每个都有自己的命令。(但它们不共享环境,因此第一个命令对后面的命令没有影响。cd

您只需要注意设置 Session 对象,而不是为每个命令创建一个新对象。

另一种选择是 shell 通道,然后将各个命令作为输入传递到远程 shell(即通过流)。但是,您必须注意不要将一个命令的输入与下一个命令混合在一起(即,仅当您知道命令正在做什么时,或者如果您有一个交互式用户,该用户可以为命令和下一个命令提供输入,并且知道何时使用哪一个命令,这才有效。


推荐