talha06 talha06 -4 years ago 50
Java Question

java.lang.Runtime exception "Cannot run program"

I am getting an exception like

java.io.IOException: Cannot run program cat /home/talha/* | grep -c TEXT_TO_SEARCH": error=2, No such file or directory
while executing the command below despite that there are no issues when I execute the same command through the terminal. I need to execute and return the output of the command below:

cat /home/talha/* | grep -c TEXT_TO_SEARCH


Here is the method used to execute commands using
Runtime
class:

public static String executeCommand(String command) {

StringBuffer output = new StringBuffer();

Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}

} catch (Exception e) {
e.printStackTrace();
}

return output.toString();
}

Answer Source

Runtime.exec does not use a shell (like, say, /bin/bash); it passes the command directly to the operating system. This means wildcards like * and pipes (|) will not be understood, since cat (like all Unix commands) does not do any parsing of those characters. You need to use something like

p = new ProcessBuilder("bash", "-c", command).start();

or, if for some bizarre reason you need to stick to using the obsolete Runtime.exec methods:

p = Runtime.getRuntime().exec(new String[] { "bash", "-c", command });

If you are only running that cat/grep command, you should consider abandoning the use of an external process, since Java code can easily traverse a directory, read lines from each file, and match them against a regular expression:

Pattern pattern = Pattern.compile("TEXT_TO_SEARCH");
Charset charset = Charset.defaultCharset();

long count = 0;

try (DirectoryStream<Path> dir =
    Files.newDirectoryStream(Paths.get("/home/talha"))) {

    for (Path file : dir) {
        count += Files.lines(file, charset).filter(pattern.asPredicate()).count();
    }
}

Update: To recursively read all files in a tree, use Files.walk:

try (Stream<Path> tree =
    Files.walk(Paths.get("/home/talha")).filter(Files::isReadable)) {

    Iterator<Path> i = tree.iterator();
    while (i.hasNext()) {
        Path file = i.next();
        try (Stream<String> lines = Files.lines(file, charset)) {
            count += lines.filter(pattern.asPredicate()).count();
        }
    };
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download