web-dev-qa-db-ja.com

JSchの「Shell」チャネルと「exec」チャネルの違いは何ですか

Javaアプリケーション内の文字列として表される多くの連続したコマンドをSSHサーバーに送信して実行できるようにしたい。

Channel channel = session.openChannel("Shell");

-または-

Channel channel = session.openChannel("exec");
28
Martin Klosi

シェルチャネルを使用すると、シェル(UNIXではshまたはbashなど、Windowsでは通常cmd.exe)が起動され、コンソールが作成されます(ローカルで実行すると画面に表示されるものと同じです)。コマンドの完了を検出するために解析または使用できるプロンプトがあります。

コマンドチャネルを使用すると、コマンドごとにシェルインスタンスが開始され(実際には、チャネルはコマンドごとに開かれます)、コマンドはシェルのパラメーターとして渡されます(Windowsでは、「cmd.exe/c」のようになります)。

コマンドチャネルを使用する方が簡単です。コマンドプロンプトを処理する必要がないためです。

JSch wikiの" Shell、Exec、またはSubsystem Channel "でこれらのストリーム間の相違点と類似点に関する概要をご覧ください。ここにあなたのユースケースのいくつかの詳細があります。

exec channel では、コマンドはsetCommand()。 SSHサーバーはそれらをすぐにシェルに渡します(bash -c '<command>'などを使用)。

なんらかの理由でシェルが何らかの理由で終了しない場合は、すべて実行されます。 (必要に応じて、ifなどを使用してロジックを実装するシェルスクリプト全体をここに送信できます。)

したがって、複数のコマンドを実行するには、それらを;または改行(\n)で区切ることにより、execチャネルに渡すことができます。すべてのコマンドを与える前に結果を待つことができないため、ここでは複数の実行チャネルしか使用できません(ただし、各チャネルは新しいシェルを生成するため、作業ディレクトリやシェル変数のように、それらの間の状態を保存しません)。

Shell channel では、シェルはストリームから入力を読み取り、最初の行を次のように解釈しますコマンド(またはいくつか)。

次に、このコマンドを実行します。コマンド自体は、必要に応じてストリームからさらに入力を読み取る場合があります。

次に、シェルは次の行を読み取り、コマンドとして解釈して実行します。

(場合によっては、シェルは複数行を読み取る必要があります。たとえば、長い文字列やifやループなどの合成コマンドの場合などです。)

これは、ストリームの最後(たとえば、ユーザー側のstream.close())または明示的なexitコマンドを実行するまで続きます。

チャネルの入力/出力ストリームを介してシェルに入力を送信しない場合、シェルは単に送信するかストリームを閉じるまで待機します。したがって、1つのコマンドの出力を静かに読み取り、クライアント側でいくつかの計算を行ってから、次に送信するコマンドを決定できます。

1つのコマンドへの入力と次のコマンドのテキストを混在させないようにしてください。できれば、標準入力から読み取るコマンドは使用しないでください。

15
Paŭlo Ebermann

まあ、私はこれがうまくいくことを発見しました、そしてあなたが通常のシェルがするように状態を保存したいなら本当に便利です:

Session session = jsch.getSession(user, Host, 22);

Channel channel = session.openChannel("Shell");

OutputStream inputstream_for_the_channel = channel.getOutputStream();
PrintStream commander = new PrintStream(inputstream_for_the_channel, true);

channel.setOutputStream(System.out, true);

channel.connect();

commander.println("ls -la");    
commander.println("cd folder");
commander.println("ls -la");
commander.println("exit");
commander.close();

do {
    Thread.sleep(1000);
} while(!channel.isEOF());

session.disconnect();

あなたは変えることができます

channel.setOutputStream(System.out, true);

InputStream outputstream_from_the_channel = channel.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(outputstream_from_the_channel));
String line;
while ((line = br.readLine()) != null)
    System.out.print(line+"\n");

出力をより詳細に制御したい場合。

================================================== ===========================

編集:フォローアップ

printStreamを介して送信するコマンドが出力にランダムに表示されることがあるのはなぜですか。つまり、次のコード:

Shell[0].println("cd ..");
Shell[0].println("cd ..");
Shell[0].println("ls -la");
Shell[0].println("exit");

これを生成します:({thing}でマークされているものはそこにあるべきではありません!)

最終ログイン:2011年7月21日木曜日21:49:13ゲートウェイから

マニフェスト:トランク最新

[ホスト〜] $ cd ..
{cd ..} [ホストホーム] $
[ホストホーム] $ cd ..
[ホスト/] $
[ホスト/] $ ls -la
{出口}

合計9999
---------- 27 root root 4096 2010年1月26日.
---------- 27ルートルート4096 2010年1月26日..
---------- 1ルートルート0 Mar 14 19:16 .autojyk
---------- 1ルートルート0 2009年2月9日.automan
---------- 1ルートルート3550 2010年5月14日.bash_history
d --------- 2 root root 4096 Apr 26 04:02 put
d --------- 5 root root 4024 Apr 25 19:31 boot
[m [ホスト/] $
[ホスト/] $出口
ログアウト

6
Martin Klosi

JSchについてはそれほどではありません。サーバーが2つのチャネルを実装する方法についてです。


一般的な* nix OpenSSHサーバー:

  • Shellチャネルは、ログインシェルを実行します(まるでSSHターミナルクライアントでログインするかのように)。シェルはコマンドプロンプトを表示し、クライアント/ユーザーがコマンドを入力するのを待ちます。 Shellチャネルの目的は、インタラクティブなシェルセッションを実装することです。これは非常にまれにしか行われません。その場合、通常は端末エミュレーションを使用します。

    Shellチャネルは、通常の状況では、SSH端末クライアント(OpenSSH sshまたはPuTTYなど)によって明らかに使用されます。

    Shellチャネルは、入力と出力を備えたブラックボックスです。入力と出力には構造がありません。たとえば、コマンドを入力に送信して実行した場合、いつ終了したかを知ることはできません。 2つのコマンドを入力キューに送信すると、どの出力がどのコマンドからのものかを区別できなくなります。

  • execコマンドは、コマンドを「引数」として受け取り、隔離された環境で実行します。これは、ユーザーのデフォルトシェルを介して行われますが、「ログイン」シェルとしては行われないため、コマンドの実行に大きな違いが生じる可能性があります。

    execチャネルの目的は、コマンドの実行を自動化することです。そのため、通常は、端末のエミュレーションを使用したくないので、ページネーション、カラーリング、主にインタラクティブな確認などの凝った操作を行うコマンドを避けます。

    execチャネルは、コマンドラインで実行するコマンドを指定するときに、OpenSSH sshまたはPuTTY plinkによって使用されます。

    ssh user@Host command
    

あまり一般的ではないSSHサーバーでは、その違いはさらに大きくなる可能性があります。サーバーによっては、チャネルの1つをサポートしていない場合もあります。また、両方がサポートされているように見えることもよくありますが、そのうちの1つ(通常はexec)が完全に壊れています。


Python/Paramikoにも同様の質問があります。
Paramikoのexec_commandとinvoke_Shell()を使用した送信の違いは何ですか?

0
Martin Prikryl