簡體   English   中英

通過 JSch shell 的多個命令

[英]Multiple commands through JSch shell

我試圖使用 JSch 庫通過 SSH 協議執行多個命令。 但我似乎卡住了,找不到任何解決方案。 setCommand()方法只能執行每個 session 的單個命令。 但我想像 Android 平台上的 connectbot 應用程序一樣按順序執行命令。 到目前為止,我的代碼是:

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

    }
}

該代碼似乎已連接到服務器,但我認為輸入和 output 數組緩沖區存在一些問題,因為根本沒有 output。 有人可以指導我如何正確處理與服務器之間的輸入和 output 以獲得所需的 output 嗎?

該命令是一個字符串,可以是遠程 shell 接受的任何內容。 嘗試

cmd1 ; cmd2 ; cmd3

依次運行多個命令。 或者

cmd1 && cmd2 && cmd3

運行命令,直到一個失敗。

即使這樣也可能有效:

cmd1
cmd2
cmd3

或在 Java 中:

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

旁注:不要將密碼和用戶名放入代碼中。 將它們放入屬性文件中,並使用系統屬性來指定屬性文件的名稱。 這樣,您甚至可以將文件保留在項目之外,並確保密碼/用戶名不會泄露。

如果您不必區分各個命令的輸入或輸出,那么 Aaron 的答案(連續給出所有命令,用\n;分隔)就可以了。

如果您必須單獨處理它們,或者在前面的命令完成之前不知道后面的命令:您可以在同一個 Session 上打開多個exec -Channels (即連接),一個接一個(即在前一個之后關閉)。 每個人都有自己的命令。 (但他們不共享環境,所以第一個中的cd命令對后面的沒有影響。)

您只需要注意使用Session object,而不是為每個命令創建一個新的。

另一種選擇是shell 頻道,然后將各個命令傳遞給遠程 shell 作為輸入(即通過流)。 但是,您必須注意不要將一個命令的輸入與下一個命令混合(即只有當您知道命令在做什么時,或者如果您有一個交互式用戶可以同時為命令和下一個命令,並且知道何時使用哪個命令。)

設置一個 SCPInfo object 來保存用戶名、密碼、端口: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);
}

盡量避免使用“shell”通道。 “shell”通道旨在實現交互式 session,而不是自動執行命令。 使用“shell”通道,您將面臨許多不需要的副作用。

要自動執行命令,請使用“exec”通道。


通常,您可以根據需要打開任意數量的“執行”通道,使用每個通道來執行您的命令之一。 您可以按順序打開通道,甚至可以並行打開。

有關“exec”通道使用的完整示例,請參閱JSch Exec.java示例

這樣,每個命令都在隔離的環境中執行。 這可能是一個優勢,但在某些情況下也可能是不受歡迎的。


如果您需要以先前命令影響以后命令的方式執行命令(例如更改工作目錄或設置環境變量),則必須在同一通道中執行所有命令。 為此,請使用服務器的 shell 的適當構造。 在大多數系統上,您可以使用分號:

execChannel.setCommand("command1 ; command2 ; command3");

在 *nix 服務器上,您還可以使用&&使以下命令僅在前面的命令成功時執行:

execChannel.setCommand("command1 && command2 && command3");

另請參閱使用 Java 中的 JSch exec 從 ArrayList 執行命令列表

在許多情況下,您甚至不需要使用多個命令。

例如,您可以在交互式使用 shell 時,而不是這個序列:

cd /path
ls

你可以做:

ls /path

最復雜的情況是,當命令相互依賴時,您需要在繼續執行其他命令之前處理先前命令的結果。

當你有這樣的需求時,它通常表明一個糟糕的設計。 仔細想想,如果這真的是解決您問題的唯一方法。 或者考慮實現一個服務器端 shell 腳本來實現邏輯,而不是從 Java 代碼遠程執行。 Shell 腳本具有更強大的技術來檢查先前命令的結果,然后您可以在 JSch 中使用 SSH 接口。

無論如何,在繼續之前,請參閱JSch Shell通道執行命令一一測試結果


旁注:不要使用StrictHostKeyChecking=no 請參閱JSch SFTP 安全與 session.setConfig("StrictHostKeyChecking", "no"); .

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM