Javaアプリケーション内で文字列として表される多数の連続したコマンドをSSHサーバーに送信して実行できるようにしたいと考えています。使用する必要があります:
Channel channel = session.openChannel("shell");
-また-
Channel channel = session.openChannel("exec");
これらのストリーム間の相違点と類似点の概要は、JSch wikiの» Shell、Exec、またはSubsystemChannel «にあります。ここにあなたのユースケースのいくつかの詳細があります。
exec
チャネルでは、コマンドは、で指定したコマンド文字列から取得されますsetCommand()
。SSHサーバーはそれらを一度にシェルに渡します(のようなものを使用しますbash -c '<command>'
)。
何らかの理由でシェルが以前に何らかの理由で終了しなかった場合、それらはすべて実行されます。if
(必要に応じて、および同様のロジックを実装するシェルスクリプト全体をここに送信できます。)
したがって、複数のコマンドを実行するには、コマンドを;
改行(\n
)で区切ってexecチャネルに渡すことができます。すべてのコマンドを実行する前に結果を待つことはできないため、ここでは複数のexecチャネルのみを使用できます(ただし、各チャネルは新しいシェルを生成するため、作業ディレクトリやシェル変数など、チャネル間の状態は保存されません)。
shell
チャネルでは、シェルはストリームから入力を読み取り、最初の行をコマンド(または複数の行)として解釈します。
次に、このコマンドを実行します。必要に応じて、コマンド自体がストリームからより多くの入力を読み取る場合があります。
次に、シェルは次の行を読み取り、それをコマンドとして解釈して実行します。
(場合によっては、シェルは複数の行を読み取る必要があります。たとえば、長い文字列や、ifやloopsなどの合成コマンドの場合です。)
これは、ストリームの終わり(たとえば、あなたの側のstream.close())または明示的な終了コマンドを実行するまで続きます。
チャネルの入出力ストリームを介してシェルに入力を送信しない場合、シェルは、さらに送信するか、ストリームを閉じるまで待機します。したがって、1つのコマンドの出力を静かに読み取り、クライアント側でいくつかの計算を実行してから、次に送信するコマンドを決定できます。
あるコマンドへの入力と次のコマンドのテキストを混同しないように注意してください。できれば、標準の入力から読み取るコマンドを使用しないでください。
シェルチャネルを使用すると、シェル(UNIXではshまたはbashなど、Windowsでは通常cmd.exe)が起動し、コンソールが作成されます(ローカルで実行した場合と同じように画面に表示されます)。コマンドの完了を解析または検出するために使用できるプロンプトがあります。
コマンドチャネルを使用すると、コマンドごとにシェルインスタンスが開始され(実際には、コマンドごとにチャネルが開かれます)、コマンドがシェルのパラメーターとして渡されます(Windowsでは「cmd.exe/c」のようになります)。
コマンドプロンプトを処理する必要がないため、コマンドチャネルを使用する方が簡単です。
さて、これが機能することを知りました。通常のシェルのように状態を保持したい場合は、非常に便利です。
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ゲートウェイから
マニフェスト:トランク-最新
[host〜] $ cd ..
{cd ..} [host home] $
[host home] $ cd ..
[host /] $
[host /] $ ls -la
{exit}合計9999
----------27ルートルート40962010年1月26日。
---------- 27 root root40962010年1月26日
..----------1 root root 0 Mar 14 19:16 .autojyk
---------- 1ルートルート02009年2月9日.automan
----------1ルートルート35502010年5月14日.bash_historyd
---------2ルートルート40964月26日04:
02putd- -------- 5 root root 4024 Apr 25 19:31 boot
[m [host /] $
[host /] $ exit
logout
JSchについてはそれほど重要ではありません。サーバーが2つのチャネルを実装する方法についてです。
一般的な*nixOpenSSHサーバー:
チャネルはログインシェルを実行します(shell
SSHターミナルクライアントでログインする場合と同じように)。次に、シェルはコマンドプロンプトを表示し、クライアント/ユーザーがコマンドを入力するのを待ちます。shell
チャネルの目的は、インタラクティブなシェルセッションを実装することです。それは非常にまれにしか行われないことです。その場合、通常はターミナルエミュレーションを使用します。
このshell
チャネルは、通常の状況では、SSHターミナルクライアント(OpenSSHssh
やPuTTYなど)によって明らかに使用されます。
shell
チャネルは、入力と出力を備えたブラックボックスです。入力と出力には構造がありません。たとえば、コマンドを入力に送信して実行した場合、コマンドがいつ終了したかを知ることはできません。2つのコマンドを入力キューに送信すると、どの出力がどのコマンドからのものかを区別できなくなります。
このexec
コマンドは、コマンドを「引数」として受け取り、分離された環境で実行します。ユーザーのデフォルトシェルを介して実行されますが、「ログイン」シェルとしては実行されないため、コマンドの実行に大きな違いが生じる可能性があります。
チャネルの目的はexec
、コマンドの実行を自動化することです。したがって、通常、端末エミュレーションを使用することは望ましくありません。これは、ページネーション、カラーリング、主にインタラクティブな確認などの凝った操作を実行するコマンドを回避するためです。
exec
チャネルは、コマンドラインで実行するコマンドを指定するときに、OpenSSHssh
またはPuTTYによって使用されます。plink
ssh user@host command
あまり一般的でないSSHサーバーでは、違いはさらに大きくなる可能性があります。一部のサーバーは、チャネルの1つをサポートしていない場合もあります。また、両方をサポートしているように見えることもよくありますが、そのうちの1つ(通常はexec
)が完全に壊れています。
Python /Paramikoにも同様の質問があり
ます。Paramikoでexec_commandとsendwithinvoke_shell()の違いは何ですか?