I recently needed to launch a MySQL backup from Java but needed to redirect stdout and stderr to file. Unfortunately, Runtime.exec() can only be used to run an executable file and pass parameters in. It does not support more complex operations such as piping the output of one process into another process or even redirecting stdout or stderr. In other words, Runtime.exec() can’t be used as a linux command line replacement.
For example, this works correctly:
Runtime.getRuntime().exec( “/usr/bin/mysqldump mydb --result-file=mydb.dump” );But this will not work:
Runtime.getRuntime().exec( “/usr/bin/mysqldump mydb --result-file=mydb.dump >stdout.txt 2>stderr.txt” );This last code fragment runs without error but the stdout.txt and stderr.txt files are not created.
The standard solution to this problem is to write Java code to launch two threads, one to read the output stream from the process and one to read the error stream and then write the output from those streams to disk from within Java, but this seems like a heavyweight solution in this instance. There is also a risk of the subprocess hanging if the Java code does not read the output from the process quickly enough, as outlined in the javadocs:
A simpler solution to allow arbitrary linux command lines to be run from Java is to write the command to a shell script and then execute the shell script. For example:
private static void runCommand(String cmd) throws IOException, InterruptedException {
// generate a script file containg the command to run
final File scriptFile = new File("/tmp/runcommand.sh");
PrintWriter w = new PrintWriter(scriptFile);
w.println( "#!/bin/sh" );
w.println( cmd );
w.close();
// make the script executable
Process p = Runtime.getRuntime().exec( "chmod +x " + scriptFile.getAbsolutePath() );
p.waitFor();
// execute the script
p = Runtime.getRuntime().exec( scriptFile.getAbsolutePath() );
p.waitFor();
}
Using this approach, I can now simply run:
runCommand(“/usr/bin/mysqldump mydb --result-file=mydb.dump >stdout.txt 2>stderr.txt”);This approach works fine for my requirement, without the overhead of creating additional Java threads. However, this approach is not suitable if the Java application needs to read the output of the process before the process has completed, in which case the standard approach of launching threads to read the output streams should be used.
The generated script approach is very convenient for enabling general purpose linux command line usage from Java.
Labels: java linux


0 Comments:
Post a Comment
<< Home