まず、ラインを交換することをお勧めします
Process process = Runtime.getRuntime ().exec ("/bin/bash");
線で
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilderはJava 5の新機能であり、外部プロセスの実行を容易にします。私の意見では、最も大きな改善点Runtime.getRuntime().exec()
は、子プロセスの標準エラーを標準出力にリダイレクトできることです。これはInputStream
、読み取るものが1つしかないことを意味します。この前に、標準出力バッファーが空のときに(子プロセスがハングする)標準エラーバッファーがいっぱいにならないようにするため、またはstdout
から読み取りをstderr
行うために、2つの別々のスレッドが必要でした。
次に、ループ(2つあります)
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
reader
プロセスの標準出力から読み取るがファイルの終わりを返す場合にのみ終了します。これは、bash
プロセスが終了したときにのみ発生します。現在、プロセスからの出力がなくなった場合、ファイルの終わりは返されません。代わりに、プロセスからの出力の次の行を待ち、この次の行があるまで戻りません。
このループに到達する前に2行の入力をプロセスに送信しているため、これらの2行の入力後にプロセスが終了しなかった場合、最初の2つのループはハングします。別の行が読み取られるのを待ちますが、読み取るための別の行はありません。
私はソースコードをコンパイルしました(現時点ではWindowsを使用しているので、に置き換え/bin/bash
ましたcmd.exe
が、原則は同じです)、次のことがわかりました。
- 2行入力すると、最初の2つのコマンドからの出力が表示されますが、プログラムがハングします。
- 私は、言う、で入力した場合
echo test
と、その後、exit
以来、プログラムは最初のループのそれを作るcmd.exe
プロセスが終了しました。次に、プログラムは別の入力行を要求し(無視されます)、子プロセスが既に終了しているため、2番目のループを直接スキップし、それ自体を終了します。
- と入力して
exit
をecho test
押すと、パイプが閉じていることを報告するIOExceptionが発生します。これは予想されることです。入力の1行目でプロセスが終了し、2行目を送信する場所がありません。
私が以前使用していたプログラムで、あなたが望んでいるように見えることと似たようなことをするトリックを見たことがあります。このプログラムはいくつかのシェルを保持し、それらの中でコマンドを実行し、これらのコマンドからの出力を読み取りました。使用されたトリックは、シェルコマンドの出力の終わりを示す「マジック」行を常に書き、それを使用して、シェルに送信されたコマンドからの出力がいつ終了したかを判断することでした。
私はあなたのコードを取り、割り当てられた行の後のすべてをwriter
次のループで置き換えました:
while (scan.hasNext()) {
String input = scan.nextLine();
if (input.trim().equals("exit")) {
// Putting 'exit' amongst the echo --EOF--s below doesn't work.
writer.write("exit\n");
} else {
writer.write("((" + input + ") && echo --EOF--) || echo --EOF--\n");
}
writer.flush();
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
System.out.println ("Stdout: " + line);
line = reader.readLine();
}
if (line == null) {
break;
}
}
これを実行した後、いくつかのコマンドを確実に実行し、各コマンドの出力を個別に返すことができました。
echo --EOF--
シェルに送信された行の2つのコマンドは、コマンド--EOF--
からのエラーの結果であっても、コマンドからの出力が確実に終了するようにするためのものです。
もちろん、このアプローチには限界があります。これらの制限は次のとおりです。
- ユーザー入力を待機するコマンド(別のシェルなど)を入力すると、プログラムがハングしたように見える
- シェルによって実行される各プロセスが出力を改行で終了すると想定しています
- シェルによって実行されているコマンドがたまたま行を書き出すと、少し混乱し
--EOF--
ます。
bash
構文エラーを報告し、不一致のテキストを入力すると終了します)
。
これらの点は、スケジュールされたタスクとして実行することを考えているものが、そのような病理学的な方法で動作しないコマンドまたはコマンドの小さなセットに制限される場合は、重要ではない場合があります。
編集:Linuxでこれを実行した後の終了処理とその他の小さな変更を改善