2

I am trying to write a java program that takes Strings in Java and replaces corresponding sequences of text in a perl script. Here is my code:

    String sedFirstLine = "'s/AAA/"+newFirstLine+"/'";
    String sedNewCntr = "'s/BBB/"+newCntr+"/'";
    String sedNewSpacing = "'s/SPACE/"+newSpacing+"/'";
    String sedNewDmax = "'s/MAX/"+newDmax+"/'";
    String sedInputFile = "/filepath/myPerlScript.pl" 
    String sedOutputFile = "/filepath/myNewPerlScript.pl";
    String[] cmdArray3 = {"sed", "-e", sedFirstLine,"-e", sedNewCntr,"-e", sedNewSpacing,"-e", sedNewDmax, "-e", sedInputFile, ">", sedOutputFile};
    Process runCmd;
    runCmd = Runtime.getRuntime().exec(cmdArray3);

When I run this program, the output file "myNewPerlScript.pl" is not generated. I'm not sure what is wrong with what I've written. The Java variables that I was referring to earlier are "newFirstLine", "newCntr", etc.

9
  • Your code never actually refers to sedOutputFile or sedInputFile. How would you expect them to be used? Commented Jul 2, 2013 at 18:41
  • 1
    Any particular reason you invoke sed instead of doing the replacement with The regular expressions already present In Java? Commented Jul 2, 2013 at 18:42
  • I copied an old version of my code. Sorry about that, but I just edited it where I actually do call sedOutputFile and sedInputFile. Commented Jul 2, 2013 at 18:44
  • I thought I had to use "sed" to replace text in a file using UNIX. It seems really convenient, but I'm just having trouble making it work with my Java code. Commented Jul 2, 2013 at 18:46
  • 1
    As general tips: Read (and implement) all the recommendations of When Runtime.exec() won't. That might solve the problem. If not, it should provide more information as to the reason it failed. Then ignore that it refers to exec and build the Process using a ProcessBuilder. Also break a String arg into String[] args to account for arguments which themselves contain spaces. Commented Jul 2, 2013 at 22:05

3 Answers 3

7

This is because the output redirection (i.e. the > ) is a functionality of the shell. In order to redirect the output of the command, you can invoke the command through a shell. For example, with this command

String[] cmdArray3 = {"bash", "-c", "sed 's/AAA/BBB/' inputfile > output"};
Process runCmd = Runtime.getRuntime().exec(cmdArray3);

the output file should be created as expected.

Sign up to request clarification or add additional context in comments.

2 Comments

Do I still need to separate each of the parameters? Or are there only three parameters: the shell, "-c", and my sed command?
@JeremyFisher You pass the entire command as a single String. Only three parameters should be passed to exec
4

The ProcessBuilder version:

String sedFirstLine = "'s/AAA/"+newFirstLine+"/'";
String sedNewCntr = "'s/BBB/"+newCntr+"/'";
String sedNewSpacing = "'s/SPACE/"+newSpacing+"/'";
String sedNewDmax = "'s/MAX/"+newDmax+"/'";

File directory = new File("/filepath");
File sedInputFile = new File(directory, "myPerlScript.pl"); 
File sedOutputFile = new File(directory, "myNewPerlScript.pl");
List<String> commandLine = new ArrayList<>();
Collections.addAll(commandLine,
    "sed",
    "-e", sedFirstLine,
    "-e", sedNewCntr,
    "-e", sedNewSpacing,
    "-e", sedNewDmax);
ProcessBuilder pb = new ProcessBuilder(commandLine);
pb.directory(directory);
pb.redirectInput(Redirect.from(sedInputFile));
pb.redirectOutput(Redirect.to(sedOutputFile));
Process sed = pb.start();
// Watch sed.getErrorStream() for errors.

See the ProcessBuilder Javadoc.

You need not worry about shells, beacuse Java takes care of the redirection, as @Chris Stratton pointed out. Just make sure you handle the error stream somehow; if there are problems and too much error output piles up, the process may block. But the original method has the same problem.

4 Comments

"Let the JRE worry about shells." - no, no shell is involved. In this case, Java is doing the redirection, not a shell.
You're right. I should have written that the programmer need not worry about shells. Another advantage of this is that the system may not have bash available, but may have sed, That's a trifle odd, but it could happen. I'll edit my post.
Yes, not depending on the shell (or the ability/syntax by which it might accept a command on its own command line) makes this answer very much worth considering for portability.
If you really wanted portability, you wouldn't resort to an external program. On the other hand, sed is probably faster than the Java equivalent.
1

Just change the following line:

String[] cmdArray3 = {"sed", "-e", sedFirstLine,"-e", sedNewCntr,"-e", sedNewSpacing,"-e", sedNewDmax, "-e", sedFile};

to:

String[] cmdArray3 = {"sed", "-e", sedFirstLine,"-e", sedNewCntr,"-e", sedNewSpacing,"-e", sedNewDmax, sedFile};

Notice the extra -e parameter that you have.

4 Comments

The extra -e parameter was actually part of my old code which I changed to ">". Sorry. But I tried it without the ">" and the file is still not being generated :/
Try it with ">" and it will work: String[] cmdArray3 = {"sed", "-e", sedFirstLine,"-e", sedNewCntr,"-e", sedNewSpacing,"-e", sedNewDmax, ">", sedOutputFile };
@user1521213 If you construct the command array like this, the output redirection character (i.e. the >) will not be parsed, but it will be passed as an argument to the command. You can either invoke the command through a shell (like in my answer), or use a ProcessBuilder, like in Eric's answer.
No, this will not work. ">" is a command to a shell, and no shell is being used here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.