2

I am executing grep command from java on a linux file. Its always returning null for the following code.

Process p;
String matchStr="testmatch";
String output = null;
try {
    String command = "grep \""+matchStr+"\" "+ filename;
    System.out.println("Running command: " + command);

    p = Runtime.getRuntime().exec(command);

    System.out.println("***********************************");
    System.out.println("***********************************");
    System.out.println("***********************************");

    p.waitFor();
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));

    while (br.readLine() != null) {
        System.out.println("in while loop");
        System.out.println("in while loop");
        System.out.println("in while loop");
        System.out.println(output);
        System.out.println("***********************************");
        System.out.println("***********************************");
        System.out.println("***********************************");
        System.out.println("***********************************");

        // Process your output here
    }

    System.out.println("exit: " + p.exitValue());
    p.destroy();
} catch (Exception e) {
    e.printStackTrace();
}

If i grep it directly it shows output but from java it never gets into while loop. Please suggest whats wrong here.

vsminkov
  • 10,912
  • 2
  • 38
  • 50
kirti
  • 4,499
  • 4
  • 31
  • 60
  • Did you give the full path of the file to be searched? `filename` does it have the full variable path? – Inian Sep 13 '16 at 14:54
  • @Inian yes its full path to the file.. also its not throwing error in reading file. – kirti Sep 13 '16 at 14:54
  • 1
    Can you run the grep invoking an explicit shell `sh` or `bash` based on your preference, like `String[] command = {"/bin/sh", "-c", "grep \""+matchStr+"\" "` ? – Inian Sep 13 '16 at 14:58
  • ok let me try that @Inian – kirti Sep 13 '16 at 15:00
  • @Inian can you provide me example for how to add filename in this command? – kirti Sep 13 '16 at 15:16
  • its getting into the loop with your suggestion thankyou @Inian – kirti Sep 13 '16 at 15:32
  • See [this post](http://stackoverflow.com/questions/31776546/why-does-runtime-execstring-work-for-some-but-not-all-commands) for why this is happening. In your case, you used `Runtime.exec(String)` with quotes. Running a shell with `/bin/sh` is one solution, but a more robust and secure alternative is to ensure `filename` and `matchStr` has no quotes or shell syntax and then use `String[] command = { "grep", matchStr, filename };` – that other guy Sep 13 '16 at 15:45

3 Answers3

4

The problem is that you do not write anything to output so it stays null. I guess you have to rewrite your while loop like this

while ((output = br.readLine()) != null) {
    // Process your output here
}

Take a note that this syntax is discouraged by most style check due to it's abmiguity

Also it's a good idea to place p.waitFor() after while loop so grep would not hang on flushig std(err|out).

UPDATE

Also it is a good idea to use ProcessBuilder (available since ) instead of Runtime.getRuntime().exec(...) because you will have more control over the process i.e

final ProcessBuilder builder = new ProcessBuilder();
builder.command("grep", matchStr, filename);

// redirect stderr to stdout
builder.redirectErrorStream(true);

final Process process = builder.start();

BufferedReader br = new BufferedReader(
    new InputStreamReader(process.getInputStream()));
String output = null;
while ((output = br.readLine()) != null) {
    System.out.println(output);

    // Process your output here
}

process.waitFor();
vsminkov
  • 10,912
  • 2
  • 38
  • 50
  • actually i was using while ((output = br.readLine()) != null) this but it wasnt working – kirti Sep 13 '16 at 15:05
  • @kirti does you program prints `in while loop` if you change while loop? – vsminkov Sep 13 '16 at 15:09
  • @kiri that means that grep failed to execute. Could you run code from update to see stderr output and write it back here? – vsminkov Sep 13 '16 at 15:30
  • thankyou.. it started working by changing the command as suggested by @inian – kirti Sep 13 '16 at 15:32
  • 1
    This solution is better because: 1. It robustly invokes grep directly, without adding a shell evaluation step, 2. It doesn't waitFor the process before reading its output, avoiding a deadlock on long output. 3. It uses ProcessBuilder, rather than the old, iffy, unextensible Runtime.exec. +1. It DOES work when used correctly, you just have to make sure that the filename and matchstring are the literal strings you want, and not e.g. add backslashes in front of spaces in any of them – that other guy Sep 13 '16 at 15:48
0

After turning your code into a https://stackoverflow.com/help/mcve it works for me.

Here the file does not exist:

robert@habanero:~$ rm /home/robert/greptest.txt

robert@habanero:~$ javac GrepTest.java && java GrepTest

Running command: grep test /home/robert/greptest.txt

exit: 2

Now the file does exist but does not contain the text to be found:

robert@habanero:~$ echo not found > /home/robert/greptest.txt

robert@habanero:~$ javac GrepTest.java && java GrepTest

Running command: grep test /home/robert/greptest.txt

exit: 1

Now the file exists and contains the text:

robert@habanero:~$ echo test this > /home/robert/greptest.txt

robert@habanero:~$ javac GrepTest.java && java GrepTest

Running command: grep test /home/robert/greptest.txt

test this

exit: 0

Here is the code:

import java.io.*;

public class GrepTest {
    public static void main(String[] args) throws Exception {
        String command = "grep test /home/robert/greptest.txt";
        System.out.println("Running command: " + command);
        Process p = Runtime.getRuntime().exec(command);
        p.waitFor();
        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String output;
        while ((output = br.readLine()) != null) {
            System.out.println(output);
        }
        System.out.println("exit: " + p.exitValue());
        p.destroy();
    }
}
Robert
  • 7,394
  • 40
  • 45
  • 64
0

I was recently struggling with a similar issue, and I believe I the solution I found is an answer also to your problem (though your question is a bit malformed as others have pointed out).

The issue pertrains to the quote marks around your search string,

\""+matchStr+"\"

The java exec command will literally deliver these to the grep command, and instead of searching for matchStr, grep will be looking for "matchStr", and the results will not be what you are expecting.

This applies also in case one is executing the command as an array like

final Process process = Runtime.getRuntime().exec(new String[] { "grep", "-C1000", searchString, fileName } );

Pass the plain searchString without including quotation marks into the string.

Martin
  • 1,385
  • 15
  • 21