web-dev-qa-db-ja.com

パイプ入力をJava bashを使用したプログラムにパイプする方法

私のJavaプログラムは標準入力をリッスンしています:

InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader bufReader = new BufferedReader(isReader);
while(true){
    try {
        String inputStr = null;
        if((inputStr=bufReader.readLine()) != null) {
            ...
        }
        else {
            System.out.println("inputStr is null");
        }
    }
    catch (Exception e) {
        ...
    }
}

ここで、bashからこのプログラムへの入力をパイプ処理したいと思います。私は以下を試しました:

echo "hi" | Java -classpath ../src test.TestProgram

しかし、それはただ印刷しているだけですinputStr is null無限の時間。私は何が間違っているのですか?

編集1:より多くのコード/コンテキストを含むように質問を更新しました。


編集2:

このOPと同じ問題が発生しているようです: Javaでのコマンドラインパイプ入力

テスト用に入力をパイプインできるようにプログラムを修正するにはどうすればよいですか?プログラムを通常実行すると、ユーザーは標準入力にも入力を入力できますか?

23
Chetan

修正しました。入力のパイプ処理が完了した後、readLine()nullを返し続けたため、無限ループがループし続けました。

修正は、readLine()がnullを返したときに無限ループから抜け出すことです。

6
Chetan

while(true)があるので、無限ループが得られます。

ループのどこかにbreakを追加することは、それを修正する1つの方法です。しかし、読者はループが終了するかどうか、いつ終了するかを確認するためにループを探し回る必要があるため、これは良いスタイルではありません。

whileステートメントに終了条件が何であるかを明確に示すようにすることをお勧めします。

String inputStr = "";
while(inputStr != null) {
    inputStr=bufReader.readLine(); 
    if(inputStr != null) {
        ...
    } else {
        System.out.println("inputStr is null");
    }
}
7
slim

私はスリムの答えが好きですが、私はそれを少し異なって扱う傾向があります。これは、テキストのストリームを1行ずつ読み取るために使用する基本的なテンプレートです。

try {
    // Wrap the System.in inside BufferedReader
    // But do not close it in a finally block, as we 
    // did no open System.in; enforcing the rule that
    // he who opens it, closes it; leave the closing to the OS.
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    String line;
    while ((line = in.readLine()) != null) {
        // TODO: Handle input line
    }

    // Null was received, so loop was aborted.

} catch (IOException e) {
    // TODO: Add error handler
}

ファイルを読んでいる場合は、少し変更して、このようにファイルを閉じます

try {
    File file = new File("some_file.txt");

    // Wrap the System.in inside BufferedReader
    // But do not close it in a finally block, as we
    // did no open System.in; enforcing the rule that
    // he who opens it, closes it; leaves the closing to the OS.
    BufferedReader in = new BufferedReader(new FileReader(file));
    try {
        String line;
        while ((line = in.readLine()) != null) {
            // TODO: Handle input line
        }

        // Null was received, so loop was aborted.

    } finally {
        try {
            in.close();
        } catch (IOException e) {
        }
    }

} catch (IOException e) {
    // TODO: Add error handler
}
4
Armand

私は何が間違っているのですか?

スニペットがそのように動作する理由はわかりません。問題はあなたが私たちに示していない何かにあると思います...

たとえば、どのバージョンのechoを使用していますか?ビルトインシェル? '/ bin'の標準のもの?あなたの検索パスにファンキーなものがありますか?

いくつかの簡単な実験を試して、問題がシェル/コマンドレベルにあるのか、Javaアプリケーション;例:.

$ echo hi > tmp
$ cat tmp
$ Java -classpath ../src test.TestProgram < tmp
$ cat tmp | Java -classpath ../src test.TestProgram

エトセトラ。

これらの実験のいずれも手がかりが得られない場合は、問題を示す小さなプログラムの実際のJavaソースコードを投稿してください。

(そして@trashgodが正しく指摘しているように、ビルド手順に「太っている」と思われ、ソースコードと一致しないバージョンのプログラムを実行している可能性があります。)

3
Stephen C

名前付きパイプ(fifos)を使用して、制御ターミナルからの両方の通常の入力を許可することを検討できます/dev/tty(または/dev/stdin)および入力FIFOを介したパイプ入力。

参照: アプリケーション(Java)の入力をリダイレクトしますが、BASHでstdinを許可します

1
jon