3

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();
1
  • 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 Commented Dec 17, 2015 at 23:26

4 Answers 4

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());
Sign up to request clarification or add additional context in comments.

2 Comments

I get an error message: Exception in thread "main" java.io.IOException: Cannot run program ".": java.io.IOException: error=13, Permission denied
instead of File.createTempFile , Create a file in the directory where you have permissions
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();
}

Comments

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

6 Comments

I'm not sure what you mean. The file items.xml never changes, how does reading the input stream make the file change?
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:docs.oracle.com/javase/7/docs/api/java/lang/Process.html
Hence the inputStream is for the process object not the file that you are running the command on.
I made changes posted above. didn't help.
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.
|
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>

2 Comments

This is not ideal for large files, as it is reading the whole file into memory.
yeah. good point. it could be converted to use a stream or a buffer.

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.