2

I'm trying to create a program to find all files by a certain name on a Linux server, and then pipe their absolute paths into an ArrayList for processing. My method of using a Process (with exec) and a BufferedReader seems to have worked for all my other needs (various other commands du -h df-h, etc...) however, it doesn't seem to be working in this case in that I get no data outputted! It does seem to be executing as it takes a minute or two to complete but I never see any data result.

Here is the code: (without try/catch which just prints stack trace)

Process process = 
    Runtime.getRuntime().exec("find " + Main.serversPath + " -name 'dynmap'");
BufferedReader stdInput = new BufferedReader(
    new InputStreamReader(process.getInputStream()));

while ((s = stdInput.readLine()) != null) {
    filesToDelete.add(s);

    if (Main.debugMode == "High") {
        System.out.println("Preprocess: dynmap pass - found " + s);
    }
}

process.destroy();
Vikdor
  • 23,934
  • 10
  • 61
  • 84
Matthew Salsamendi
  • 294
  • 1
  • 5
  • 14

3 Answers3

1

This line:

System.out.println("Preprocess: dynmap pass - found " + s);

is likely not getting executed.

When used on Strings the == operator compares the object references instead of the values.

In order to compare the actual values you should use the String.equals() method:

if (Main.debugMode.equals("High")) {
    System.out.println("Preprocess: dynmap pass - found " + s);
}

See here for an overview of comparing Objects in Java

knoight
  • 479
  • 8
  • 18
  • Yes :), I'm aware, just some lazy code. Regardless this does not fix the issue as I've verified that the BufferedReader is receiving no output. – Matthew Salsamendi Dec 20 '12 at 05:48
  • Everything looks ok. Based on your comment that @Vikdor's solution did not help, all I can guess is that something is not correct with your find command? It has been a long time since I've really done anything on a linux box, but I found this: "If find doesn't locate any matching files, it produces no output." [here](http://content.hccfl.edu/pollock/unix/findcmd.htm). Perhaps your `Main.serversPath` variable is not what you expect? – knoight Dec 20 '12 at 13:05
  • I've printed the output of the full command string and then pasted that into the console regularly and it returns 3 files perfectly fine. So I'm 100% sure that the syntax getting passed in is proper. – Matthew Salsamendi Dec 20 '12 at 15:52
1

You should always capture the error stream of a process in a separate thread (using a StreamGobbler) to handle the cases where the process throws errors.

class StreamGobbler extends Thread
{
    private InputStream is;
    private String myMessage;

    public StreamGobbler(InputStream istream)
    {
        this.is = istream;
    }

    public String getMessage()
    {
        return this.myMessage;
    }

    @Override
    public void run()
    {
        StringBuilder buffer = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        int size = 1024 * 1024;
        char[] ch = new char[size];
        int read = 0;
        try {
            while ((read = br.read(ch, 0, size)) >= 0) {
                buffer.append(ch, 0, read);
            }
        }
        catch (Exception ioe) {
            ioe.printStackTrace();
        }
        finally {
            try {
                br.close();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.myMessage = buffer.toString();
        return;
    }
}

Then you should use the StreamGobbler to capture error stream as follows:

Process process = 
    new ProcessBuilder("find", Main.serversPath, "-name", "'dynmap'").start();

StreamGobbler error = new StreamGobbler(process.getErrorStream());
error.start();

BufferedReader stdInput =
    new BufferedReader(new InputStreamReader(process.getInputStream()));

while ((s = stdInput.readLine()) != null) {
    filesToDelete.add(s);

    if (Main.debugMode.equals("High")) {
        System.out.println("Preprocess: dynmap pass - found " + s);
    }
}

// Get the exit status
int exitStatus = process.waitFor();
if (exitStatus != 0) {
    // read the error.getMessage() and handle accordingly.
}
process.destroy();

Also, it is recommended to use the ProcessBuilder to create a process.

Vikdor
  • 23,934
  • 10
  • 61
  • 84
  • Thanks for taking the time to help out. Unfortauntly this did not help solve the issue. Zero output from the error stream. – Matthew Salsamendi Dec 20 '12 at 05:56
  • A couple of things you could try: 1. print the command and run it directly from the command line. 2. Specify the complete path of `find` command being used. – Vikdor Dec 20 '12 at 07:03
  • I have done that Vikdor and it works fine. I tried specifying the full path, /usr/bin/find and that did not work either. – Matthew Salsamendi Dec 20 '12 at 15:51
0

I think your problem is that you are not closing your BufferedRreader. You should ALWAYS close and if nesasary, flush your streams. So:

    Process process = Runtime.getRuntime().exec("find " + Main.serversPath + " -name 'dynmap'");
    BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));

    while ((s = stdInput.readLine()) != null) {
        filesToDelete.add(s);

        if (Main.debugMode == "High") {
            System.out.println("Preprocess: dynmap pass - found " + s);
        }
    }
    process.destroy();
    //Add this line here!
    stdInput.close();

You may also want to change this:

    if (Main.debugMode == "High") {
            System.out.println("Preprocess: dynmap pass - found " + s);
    }

to this:

   if (Main.debugMode.equals("High")) {
            System.out.println("Preprocess: dynmap pass - found " + s);
   }
Alex Orzechowski
  • 377
  • 4
  • 12
  • Closing the `BufferedReader` really shouldn't make a difference. I have only ever seen flushing / closing a stream trip people up when it's an `OutputStream`. – Jeffrey Dec 20 '12 at 02:01
  • Neither of these would fix the issue, but it is good coding pratices, I wasn't aware of closing BRs but I was going to change it to .equals (just some lazy code) – Matthew Salsamendi Dec 20 '12 at 05:49