1

I am running my Java program from terminal and I am trying to count the number of files in a certain directory using a linux command in my code; I have managed to get output for all other commands but this one.

My command is: ls somePath/*.xml | wc -l

When I run my command in my code, it appears that it has nothing to output, yet when I run the same exact command in terminal it works just fine and actually outputs the number of xml files in that directory.

Here is my code:

private String executeTerminalCommand(String command) {
    String s, lastOutput = "";
    Process p;
    try {
        p = Runtime.getRuntime().exec(command);
        BufferedReader br = new BufferedReader(
                new InputStreamReader(p.getInputStream()));
        System.out.println("Executing command: " + command);
        while ((s = br.readLine()) != null){//it appears that it never enters this loop since I never see anything outputted 
            System.out.println(s);
            lastOutput = s;
        }
        p.waitFor();
        p.destroy();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return lastOutput;//returns empty string ""
}

Updated code w/ output

private String executeTerminalCommand(String command) {
        String s, lastOutput = "";
        try {
            Process p = new ProcessBuilder().command("/bin/bash", "-c", command).inheritIO().start();           
            //Process p = Runtime.getRuntime().exec(command);
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(p.getInputStream()));
            System.out.println("Executing command: " + command);
            while ((s = br.readLine()) != null){
                System.out.println("OUTPUT: " + s);
                lastOutput = s;
            }
            System.out.println("Done with command------------------------");
            p.waitFor();
            p.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("LAST OUTPUT IS: " + lastOutput);
        return lastOutput;
    }

output:

Executing command: find my/path -empty -type f | wc -l
Done with command------------------------
1
LAST OUTPUT IS:
mr nooby noob
  • 1,860
  • 5
  • 33
  • 56
  • maybe try using ProcessBuilder and doing `pb.redirectErrorStream(true);` – Scary Wombat Aug 26 '16 at 00:10
  • Try this command: `Process p = new ProcessBuilder().command("bash", "-c", "ls somePath/*.xml | wc -l").inheritIO().start();` –  Aug 26 '16 at 00:14
  • Thank you guys, but unfortunately those did not work for me. – mr nooby noob Aug 26 '16 at 00:19
  • try to fully path your path. Also see this SO about pipes http://stackoverflow.com/questions/3776195/using-java-processbuilder-to-execute-a-piped-command – Scary Wombat Aug 26 '16 at 00:22
  • The argument to exec is a program; you're passing in a string representing a program _ and its arguments_, with pipes to boot. You need to either use a different overload and multiple calls, with output stream from the first feeding into the next -- or run your command in a shell. – yshavit Aug 26 '16 at 00:26
  • 1
    @mrnoobynoob The command works fine on my machine( it outputs the no. of lines). Can you post your code, including my suggestion? –  Aug 26 '16 at 00:29
  • Also, if what you really want is just the count of XML files, check out https://docs.oracle.com/javase/7/docs/api/java/io/File.html#listFiles(java.io.FilenameFilter) – yshavit Aug 26 '16 at 00:30
  • @SkrewEverything and ScaryWombat, Sorry, I don't know what I did different this time, but your guys' solutions work! Thank you! – mr nooby noob Aug 26 '16 at 00:32
  • @mrnoobynoob "I don't know what I did different this time". You should know. You can't do programming on the basis of **Trial and Error** method. –  Aug 26 '16 at 00:37
  • @SkrewEverything I know, I am working my way back to see what I did different. – mr nooby noob Aug 26 '16 at 00:38
  • If you are using a IDE like eclipse you can view the local history of your changes. As it is, this Question is of no use for anyone – Scary Wombat Aug 26 '16 at 00:41
  • @SkrewEverything I found out what I did wrong, but I still don't understand why I am getting the following result: it turns out that your solution does in fact display the value on the screen, but I am unable to store it as a variable (that was my confusion). Do you know why this could be? I have updated my code and posted the output. – mr nooby noob Aug 26 '16 at 00:56
  • @mrnoobynoob That's because you have already redirected the stream to console with `inheritIO()`. Just remove it and you can see your mentioned output. –  Aug 26 '16 at 01:01
  • Have you considered counting these files with pure Java? It would be faster and take less code. – Elliott Frisch Aug 26 '16 at 01:10
  • `Runtime.getRuntime().exec(new String[] { "/bin/bash", "-c", "ls somePath/*.xml | wc -l" })` works fine on my machine – Saravana Aug 26 '16 at 03:27
  • @SkrewEverything You're awesome, thank you very much! – mr nooby noob Aug 26 '16 at 16:17

1 Answers1

2

To execute a pipeline, you have to invoke a shell, and then run your commands inside that shell.

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

bash invokes a shell to execute your command and -c means commands are read from string. So, you don't have to send the command as an array in ProcessBuilder.

But if you want to use Runtime then

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

Note: You can check advantages of ProcessBuilder here and features here over Runtime

Community
  • 1
  • 1
  • 1
    It's nice to see the answer using both `ProcessBuilder` and `Runtime`. Most of the answers suggest to use `ProcessBuilder` and answer the code in `ProcessBuilder`. It really helped. Thanks! – SkrewEverything Aug 26 '16 at 23:45