Search code examples
javashellgrepprocessbuilderherestring

One does not simply grep into ProcessBuilder


does anyone know how to use linux grep with the java ProcessBuilder? Why does this code return an empty string when it should return "sing" ?

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);     
}
}

I also try to echo what I execute with this code:

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

and get the correct result:

 grep "sing" <<<"sing"

I finally try to execute the command at the shell and get:

sing

although it is in red font for some reason. So what am I doing wrong?


Solution

  • what am I doing wrong?

    Something which is pretty obvious.

    Do you expect, say, execve(), to understand shell constructs? No.

    Well, you shouldn't be expecting ProcessBuilder to understand those either. Although it is not as low level as execve(), it is low level enough that the arguments to a command are "raw". Therefore, in your command, <<<"sing" is passed as is as an argument to grep; which means grep views it as a file to read from.

    Get that in your head: what you type in the shell is interpreted by the shell; a ProcessBuilder WILL NOT use a shell to execute its processes, nor will execve(). Which, in turn, means that you cannot use shell constructs.

    If you want to grep you'll have to feed your process' input with the text you want. But why use grep when Java has a builtin regex engine is another question, of course.

    As to:

    although it is in red font for some reason

    it is simply text decoration from the grep command (well, GNU grep at least); see its manpage and the --color option. In short, in your case, it has detected that your tty had the capabilities to change the color of text and it uses that to decorate the matched text.

    Try and:

    echo foobar | grep foo
    

    It will echo foobar with foo in red.