2

I am trying to run a sed command from java without success. Here is my java code:

String[] cmd = {"sed", "-i", "'"+lineIndex+"s/"+line+"/"+currentBid+"/g'", "/data/jsp/items.xml"};
        Runtime.getRuntime().exec(cmd);

I also tried:

String[] cmd = {"/bin/sh","-c","sed", "-i", "'"+lineIndex+"s/"+line+"/"+currentBid+"/g'", "/data/jsp/items.xml"};
        Runtime.getRuntime().exec(cmd);

Thing is, if I print out the contents of the cmd String and run it in a terminal it does work. It's just not executing it from java for some reason. Te make this more clear, when I run the command directly from a terminal the file "items.xml" changes. When I run it from java the file does not change. I've verified that the command is correct as sown below.

Am I missing something?

The output from cmd is sed -i '21s/2/102/g' /data/jsp/items.xml

** EDIT

I made the following changes based on comments below. No change in output however.

String[] cmd = {"/bin/sh","-c","sed", "-i", "'"+lineIndex+"s/"+line+"/"+currentBid+"/g'", "/data/jsp/items.xml"};
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();

BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line2 = reader.readLine();
while (line2 != null) {
     line2 = reader.readLine();
}
reader.close();
cHam
  • 2,624
  • 7
  • 26
  • 28
  • Seems like it would be better, to me, to stream the XML in Java and do the search and replace in Java rather than executing `sed` from an external shell – Kirby Dec 17 '15 at 23:26

4 Answers4

1

You should probably use a ProcessBuilder instead of Runtime.exec, perhaps something like this -

try {
  String replaceCommand ="'"+lineIndex+"s/"+line+"/"+currentBid+"/g'";
  String [] cmd = new String[] {
      "sed", "-i", replaceCommand, "/data/jsp/items.xml"  
  };
  Process process = new ProcessBuilder(cmd)
      .start();
  InputStream is = process.getInputStream();
  InputStreamReader isr = new InputStreamReader(is);
  BufferedReader br = new BufferedReader(isr);
  String lineRead;

  System.out.printf("Output of running %s is:",
      Arrays.toString(cmd));

  while ((lineRead = br.readLine()) != null) {
    System.out.println(lineRead);
  }
} catch (IOException e) {
  e.printStackTrace();
}
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
1

You need to make sure the path to the file is correct, java may not have the same path to the file unless it is in the jar. You can do this by trying to open the file or checking if it exists before passing it to the command.

see: How to read file from relative path in Java project? java.io.File cannot find the path specified

Community
  • 1
  • 1
Cory Koch
  • 470
  • 4
  • 8
  • I'm not sure what you mean. The file items.xml never changes, how does reading the input stream make the file change? – cHam Nov 27 '13 at 02:30
  • Sorry I did not realize that the example was missing the type of p. p is of type process you access the output see:http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html – Cory Koch Nov 27 '13 at 02:38
  • Sorry I did not realize that the example was missing the type of p. p is of type process you access the output through its getInputStream method. see:http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html – Cory Koch Nov 27 '13 at 02:44
  • Hence the inputStream is for the process object not the file that you are running the command on. – Cory Koch Nov 27 '13 at 02:45
  • I made changes posted above. didn't help. – cHam Nov 27 '13 at 02:46
  • I cannot comment on your change above so I will do it here. Add a System.out.println(line); to the inside of the while loop to see the output. – Cory Koch Nov 27 '13 at 02:47
  • I'll add that I have done this multiple times before and it worked fine. Just not working with sed for some reason. – cHam Nov 27 '13 at 02:47
1

Try that :)

The advantage of this solution , it's more easier to debugging because you have the temporary file !

String lineIndex="21";
String line="2";
String currentBid="102";

File temp = File.createTempFile("temp-sh", ".sh"); 



FileWriter fw = new FileWriter(temp);
fw.write("#!/bin/bash\n");
fw.write("sed -i '"+lineIndex+"s/"+line+"/"+currentBid+"/g' data/jsp/items.xml\n");
fw.close();
System.out.println(". "+temp.getAbsolutePath());
Runtime.getRuntime().exec(". "+temp.getAbsolutePath());
L. Quastana
  • 1,273
  • 1
  • 12
  • 34
  • I get an error message: Exception in thread "main" java.io.IOException: Cannot run program ".": java.io.IOException: error=13, Permission denied – cHam Nov 27 '13 at 02:55
  • instead of File.createTempFile , Create a file in the directory where you have permissions – L. Quastana Nov 27 '13 at 02:59
0

Honestly there is no need to externally execute sed in this case. Read the file in Java and use Pattern. Then you have code that could run on any platform. Combine this with org.apache.commons.io.FileUtils and you can do it in a few lines of code.

    final File = new File("/data/jsp/items.xml");    
    String contents = FileUtils.readFileToString(file, StandardCharsets.UTF_8.name());
    contents = Pattern.compile(line).matcher(contents).replaceAll(currentBid);
    FileUtils.write(file, contents);

Or, in a short, self-contained, correct example

    import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;

public final class SedUtil {

    public static void main(String... args) throws Exception {
        final File file = new File("items.xml");
        final String line = "<bid>\\d+</bid>";
        final String currentBid = "<bid>20</bid>";
        final String data = "<bids><bid>10</bid></bids>";
        FileUtils.write(file, data);
        sed(file, Pattern.compile(line), currentBid);
        System.out.println(data);
        System.out.println(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
    }

    public static void sed(File file, Pattern regex, String value) throws IOException {
        String contents = FileUtils.readFileToString(file, StandardCharsets.UTF_8.name());
        contents = regex.matcher(contents).replaceAll(value);
        FileUtils.write(file, contents);
    }
}

which gives output

<bids><bid>10</bid></bids>
<bids><bid>20</bid></bids>
Kirby
  • 15,127
  • 10
  • 89
  • 104