There are two solutions to this problem, both of which sacrifice platform independence. The first is to make use of native methods in your Java code. You lose the portability, but achieve the result. Native methods can also be more difficult to implement, which can make them less desirable to use.
The second option is to satisfy the programming needs by executing external utilities and applications from within a Java program. In Java, this means employing the Runtime class exec() method. Like the fork(3) C function, Runtime.exec() allows you to execute a program; unlike fork(), it does not allow you to directly control the environment. Runtime.exec() provides a simple interface to platform-dependent utilities and applications, although at the expense of platform independence. In an environment where Java applications must coexist with other non-Java applications this will often be a valid trade-off.
In its simplest form, exec() is quite easy to use:
Process p = Runtime.getRuntime().exec("/bin/ls");The problem with this form is that it gets you nowhere. When Java forks a new process it redirects STDIN, STDOUT and STDERR. Therefore the results of
"/bin/ls"
do not go to the screen. Instead you must use the
getInputStream(), getOutputStream() and getErrorStream() methods of the
Process object to communicate with the program that you executed. Listing 1
shows an example using the Unix ls(1) command.
Listing 1 import java.io.*; class execInput { public static void main(String Argv[]) { try { String ls_str; Process ls_proc = Runtime.getRuntime().exec("/bin/ls -aFl"); // get its output (your input) stream DataInputStream ls_in = new DataInputStream( ls_proc.getInputStream()); try { while ((ls_str = ls_in.readLine()) != null) { System.out.println(ls_str); } } catch (IOException e) { System.exit(0); } } catch (IOException e1) { System.err.println(e1); System.exit(1); } System.exit(0); } }Some points to be aware of with this code. In the JDK1.0.2 implementation, you must supply a complete path to whatever it is that you are executing. There is no facility in that version of the JDK to get the shell environment that you are running in, hence no PATH variable is known. This is fixed in JDK1.1, however it is always good practice to fully qualify the path. Shell built-in commands will not work here. A prime example of this is the DOS "dir" command. This is a built-in and will not execute. You would need to use "
command \c dir
" as the command string.If you pass the executable command as a single String, the exec() method will break the string into multiple strings, breaking the original string on white space. This will cause some trouble when trying to do things like I/O redirection.
Consider the following line of code:
Process p = Runtime.getRuntime().exec("/bin/sh -c /bin/ls > ls.out");This is intended to execute a Bourne shell and have the shell execute the ls command, redirecting the output of ls to the file ls.out. The reason for using /bin/sh is to get around the problem of having stdout redirected by the Java internals. Unfortunately, if you try this nothing will happen. When this command string is passed to the exec() method it will be broken into an array of Strings with the elements being
"/bin/sh", "-c", "/bin/ls",
">", and "ls.out"
. This will fail, as sh expects only a single
argument to the "-c" switch. To make this work try:
String[] cmd = {"/bin/sh", "-c", "/bin/ls > out.dat"}; Process p = Runtime.getRuntime().exec(cmd);Since the command line is already a series of Strings, the strings will simply be loaded into the command array by the exec() method and passed to the new process as is. Thus the shell will see a "-c" and the command "
/bin/ls > ls.out
" and execute correctly.
Using Runtime.exec() can make integration with system utilities, tools and
legacy software achievable, although, as already noted, at the expense
platform independence. If you must work with existing software and tools, it
is often the easiest, and most straight-forward approach to the problem. But
beware of the gotchas. They can often lead to unexpected results.
It shows you a trick to deal with redirection of commands output in shell
ReplyDelete