burnedWood
burnedWood

Reputation: 93

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?

Upvotes: 1

Views: 2731

Answers (2)

fge
fge

Reputation: 121760

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.

Upvotes: 3

anubhava
anubhava

Reputation: 785376

You can actually run the same command using ProcessBuilder but you have to make sure it is execute by bash. I prefer this utility method:

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

Then call it as:

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

And it gives me this output:

sing

Upvotes: 1

Related Questions