3

Java プログラムを Linux bash と対話させようとしていますが、問題が発生します。prog1 つの整数を読み取り、stdinその 2 乗を出力する単純な実行可能ファイルがあります。実行中

echo 5 | ./prog

bash自体から、実行中の正しい答えが25出力されますstdout

import java.io.*;

public class Main {
    public static void main(String[] args) throws InterruptedException, IOException {
        Runtime run = Runtime.getRuntime();
        Process proc = run.exec("echo 5 | ./prog");
        proc.waitFor();
        BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        while(br.ready())
            System.out.println(br.readLine());
    }
}

意外とくれ5 | ./progます。解決策は何ですか?

4

1 に答える 1

12

Javaexecはそのようなシェル コマンドを実行できません。シェル コマンドを実行する場合は、シェルを明示的に呼び出す必要があります。例えば

Process proc = run.exec(new String[]{"/bin/sh", "-c", "echo 5 | ./prog"});

これに対する Java の機能の詳細については、exec(String)およびの javadoc を参照してくださいexec(String[])。これらは「便利なメソッド」であり、javadoc の内容を完全に理解するには、基礎となるメソッドへの一連のリンクをたどる必要があることに注意してください。

Javaがこれを処理する方法についてさらに詳しく知りたい場合は、ソースコードがあります...

Java がシェル構文自体を処理しない理由を詳しく理解したい場合は、おそらく UNIX/Linux システムのアーキテクチャと哲学、およびアプリケーション、オペレーティング システム、コマンド シェル間の関心の分離について深く掘り下げる必要があります。 . 無数の異なるシェルがあり、それぞれが引用、引数分割、リダイレクト、パイプなどの (潜在的に) 異なるルールを持っていることに注意してください。人気のあるシェルのほとんどは似ていますが、それは物事がうまくいった方法です.

解決策の説明:

  • コマンドを手動で分割する理由は、コマンドを単一のコマンドと引数に正しくexec(String)分割しないためです。できません。これは、パイプラインに 2 つのコマンドがある例です。

  • 「sh」を使用する理由は...まあ...シェルコマンドラインを解析して処理するシェルが必要だからです。Javaのexecコマンドはシェル構文をサポートしていません... Javadocが説明しているように。

  • 「-c」オプションの目的は、「man sh」で説明されています。基本的にsh -c "a b c"は、「「sh」を使用してコマンドライン「ab c」を実行する」ことを意味します。

参考までに、パイプラインを Java だけで (つまり、外部シェルに依存せずに) 構築して実行することは技術的に可能ですが、一般的には努力する価値はありません。外部コマンドを実行することにより、既にプラットフォームの依存関係が導入されているため、特定のシェル コマンドと構文の形で追加の依存関係が発生しても、状況が大幅に悪化することはありません。

于 2013-08-25T00:42:17.367 に答える