Seseorang tidak hanya masuk ke dalam ProcessBuilder

apakah ada yang tahu cara menggunakan linux grep dengan Java ProcessBuilder? Mengapa kode ini mengembalikan string kosong padahal seharusnya mengembalikan "bernyanyi"?

import java.io.*;
import java.util.*;

public class Test2 {

public static void main(String[] args) throws InterruptedException,IOException{
    String line;

    // Initiate grep process.
    ProcessBuilder pb = new ProcessBuilder("grep", "\"sing\"", "<<<\"sing\"");
    Process p = pb.start();
    p.waitFor();

    // Get grep output:     
    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

    StringBuilder builder = new StringBuilder();
    line = null;
    while ( (line = reader.readLine()) != null) {
        builder.append(line);
        builder.append(System.getProperty("line.separator"));
    }
    String result = builder.toString();
    System.out.println(result);     
}
}

Saya juga mencoba mengulangi apa yang saya jalankan dengan kode ini:

ProcessBuilder pb = new ProcessBuilder("echo","grep", "\"sing\"", "<<<\"sing\"");

dan dapatkan hasil yang benar:

 grep "sing" <<<"sing"

Saya akhirnya mencoba menjalankan perintah di Shell dan mendapatkan:

sing

meskipun fontnya merah karena alasan tertentu. Jadi apa yang saya lakukan salah?


person burnedWood    schedule 30.01.2015    source sumber
comment
Dalam contoh Anda, grep mengambil satu argumen (bernyanyi), dan simbol <<< memberitahu shell untuk meneruskan apa pun yang berikut sebagai aliran input ke grep. Kode ProcessBuilder Anda memperlakukan simbol aliran masukan sebagai argumen lain.   -  person Brian    schedule 31.01.2015


Jawaban (2)


apa yang aku lakukan salah?

Sesuatu yang cukup jelas.

Apakah Anda berharap, katakanlah, execve(), untuk memahami konstruksi shell? TIDAK.

Ya, Anda juga tidak seharusnya mengharapkan ProcessBuilder untuk memahaminya. Meskipun levelnya tidak serendah execve(), level ini cukup rendah sehingga argumen suatu perintah bersifat "mentah". Oleh karena itu, dalam perintah Anda, <<<"sing" diteruskan apa adanya sebagai argumen ke grep; yang berarti grep melihatnya sebagai file untuk dibaca.

Ingatlah hal itu: apa yang Anda ketik di shell ditafsirkan oleh shell; a ProcessBuilder TIDAK AKAN menggunakan shell untuk menjalankan prosesnya, begitu pula execve(). Hal ini berarti Anda tidak dapat menggunakan konstruksi shell.

Jika Anda ingin grep Anda harus masukan masukan proses Anda dengan teks yang Anda inginkan. Tapi mengapa menggunakan grep ketika Java memiliki mesin regex bawaan tentu saja merupakan pertanyaan lain.

As to:

meskipun fontnya merah karena alasan tertentu

itu hanyalah hiasan teks dari perintah grep (setidaknya GNU grep); lihat halaman manualnya dan opsi --color. Singkatnya, dalam kasus Anda, ia mendeteksi bahwa tty Anda memiliki kemampuan untuk mengubah warna teks dan menggunakannya untuk menghias teks yang cocok.

Coba dan:

echo foobar | grep foo

Ini akan menggemakan foobar dengan foo berwarna merah.

person fge    schedule 30.01.2015
comment
Kepada penjawab meskipun Anda memposting jawaban yang benar, Anda terlalu sombong atau kasar kepada OP dengan mengabaikan fakta bahwa apa yang tampak jelas bagi Anda bisa menjadi misteri bagi penanya, jika dia tahu lalu apa gunanya bertanya? - person qualebs; 29.05.2017
comment
@qualebs Oke, saya setuju, saya dapat mengulangi jawaban saya, tetapi yang membuat saya bingung adalah ini adalah pemrograman OS 101. Bahwa (non) kehalusan semacam ini masih belum diajarkan dalam kursus pemrograman pada tahun 2017 membuat saya bingung - person fge; 29.05.2017

Anda sebenarnya dapat menjalankan perintah yang sama menggunakan ProcessBuilder tetapi Anda harus memastikan perintah tersebut dijalankan oleh bash. Saya lebih suka metode utilitas ini:

public static int runCmd(final String command) {
    Process process=null;
    int ret = 0;
    String[] finalCommand = new String[] { "bash", "-c", command };

    try {
        final ProcessBuilder processBuilder = new ProcessBuilder(finalCommand);
        processBuilder.redirectErrorStream(true);
        process = processBuilder.start();
        ret = process.waitFor();
        // stdout+stderr
        InputStreamReader isr = new InputStreamReader( process.getInputStream() );
        BufferedReader br = new BufferedReader(isr);
        String line;
        while ((line = br.readLine()) != null) {
          System.out.println(line);
        }
        //System.out.println("Program terminated!");
        process.destroy();
        br.close();
        isr.close();
    } 
    catch (IOException|InterruptedException e) { 
        e.printStackTrace(); 
    } 
    return ret;
}

Kemudian sebut saja sebagai:

runCmd("grep -o \"sing\" <<<\"icansing\"");

Dan itu memberi saya keluaran: ini

sing
person anubhava    schedule 30.01.2015
comment
Meskipun hal ini mungkin terjadi, hal ini hampir tidak pernah merupakan hal yang benar untuk dilakukan; bisa dikatakan, ia berada pada tingkat kejahatan yang sama dengan sistem yang terkenal itu()... - person fge; 31.01.2015
comment
Itu tetap tidak akan menghentikan pemrogram menggunakan system() dan sejujurnya ada beberapa kasus yang valid untuk melakukannya (bukan grep ini) - person anubhava; 31.01.2015
comment
Sepertinya itu adalah metode yang berguna untuk dimiliki. Juga @fge dengan asumsi Anda merujuk ke fungsi C system(), mengapa ini begitu terkenal? Adakah tautan yang ingin Anda bagikan? - person burnedWood; 01.02.2015