2

I'm having some problems with a certain segment of my code. What is supposed to happen is that the Java program takes some predetermined variables and uses UNIX's "sed" function to replace the Strings "AAA" and "BBB" in a pre-written shell script. I have three methods to do this: one that replaces the Strings in the file using "sed" and writes the output to a different file; one that removes the original file with the "rm" command; and one that renames the output file to the name of the original file using "mv". There are three copies of the shell script in three different directories, and each one should be replaced with it's own specific variables.

The replacement should occur for all three shell script files, but it only occurs for two. On the third shell script, it seems as if the process did not complete, because the byte size of that file is 0. The file that is not replaced is completely random, so it's not the same file not working during each run.

I'm not sure why this error is occuring. Does anyone have any possible solutions? Here is the code:

    public void modifyShellScript(String firstParam, String secondParam, int thirdParam, int fourthParam, String outfileDirectoryPath) throws IOException{
    String thirdDammifParamString = "";
    String fourthDammifParamString = "";
    thirdDammifParamString = Integer.toString(thirdDammifParam);
    fourthDammifParamString = Integer.toString(fourthDammifParam);
    String[] cmdArray3 = {"/bin/tcsh","-c", "sed -e 's/AAA/"+firstDammifParam+"/' -e 's/BBB/"+secondDammifParam+"/' -e 's/C/"+thirdDammifParamString+"/' -e 's/D/"+fourthDammifParam+"/' "+outfileDirectoryPath+"runDammifScript.sh > "+outfileDirectoryPath+"runDammifScript.sh2"};
    Process p;
    p = Runtime.getRuntime().exec(cmdArray3);
}

public void removeOriginalShellScript(String outfileDirectoryPath) throws IOException{
    String[] removeCmdArray = {"/bin/tcsh", "-c", "rm "+outfileDirectoryPath+"runDammifScript.sh"};
    Process p1;
    p1 = Runtime.getRuntime().exec(removeCmdArray);
}

public void reconvertOutputScript(String outfileDirectoryPath) throws IOException{
    String[] reconvertCmdArray = {"/bin/tcsh","-c","mv "+outfileDirectoryPath+"runDammifScript.sh2 "+outfileDirectoryPath+"runDammifScript.sh"};
    Process reconvert; 
    reconvert = Runtime.getRuntime().exec(reconvertCmdArray);
}
Jeremy Fisher
  • 2,510
  • 7
  • 30
  • 59
  • Why not just use Java to do the string replacement instead of sed? – rob Aug 14 '13 at 18:20
  • UNIX functionality seems to work a lot better with file parsing. Besides, I didn't want to have to deal with reading from the file, finding the specific CHAR sequence "AAA", and replacing that. It's a good idea without a doubt, but I only have three more hours to finish this script and this problem just occurred. – Jeremy Fisher Aug 14 '13 at 18:23

1 Answers1

2

If you haven't already, take a look at When Runtime.exec() won't. One or more Process might be hanging because you aren't consuming the output and error streams. In particular, look at the StreamGobbler in that article's examples.

It could also be the case that you're forgetting to include a trailing slash in outfileDirectoryPath. Read the Process' error stream to see what's going wrong:

InputStream err = p.getErrorStream();
// read the stream and print its contents to the console, or whatever

Keep in mind that you'll want to read the streams in separate threads.

That said, I would personally just do all of this natively in Java instead of relying on external, platform-specific dependencies.

For substring replacement, read the file to a String, then use String.replace and/or String.replaceAll.

You can replace removeOriginalShellScript's body with a call to File.delete:

public void removeOriginalShellScript(String outfileDirectoryPath) throws IOException{
    File f = new File(outfileDirectoryPath, "runDammifScript.sh");
    f.delete();
}

You can replace reconvertOutputScript's body with a call to Files.move:

public void reconvertOutputScript(String outfileDirectoryPath) throws IOException{
    File src = new File(outfileDirectoryPath, "runDammifScript.sh2");
    File dst = new File(outfileDirectoryPath, "runDammifScript.sh");
    Files.move(src, dst);
}

Or just replace both removeOriginalShellScript and reconvertOoutputScript with a call to Files.move, specifying the REPLACE_EXISTING option:

File src = new File(outfileDirectoryPath, "runDammifScript.sh2");
File dst = new File(outfileDirectoryPath, "runDammifScript.sh");
Files.move(src, dst, REPLACE_EXISTING);
Community
  • 1
  • 1
rob
  • 6,147
  • 2
  • 37
  • 56
  • Thank you very much for an excellent answer. I did not Java had this functionality. However, I would like to keep this as a last resort, because this function is a BIG portion of my code and it would take a lot of time to incorporate these functions into my methods and replace all necessary lines. However, I am curious as to why my methods work for two of my files and not for the third. It seems as if it's not a problem with how I've written my code, but with something else instead. – Jeremy Fisher Aug 14 '13 at 18:37
  • If you want to keep the same API, you can simply replace the contents of your existing methods with these simpler, pure Java implementations. The cause of your hanging processes could be something as simple as Process' streams not being consumed. – rob Aug 14 '13 at 18:44
  • I updated my answer to demonstrate how you can replace your implementations while preserving your existing API. I also added some debugging tips; hope it helps. – rob Aug 14 '13 at 19:03
  • Actually, I don't have Java 7, but your modification for the "reconvertOutputScript" method is elegant. Thank you. – Jeremy Fisher Aug 15 '13 at 13:34