C system() equivalent method.
Hello (before to start, sorry for my bad english) I have seen in the last JDK's build that ProcessBuilder allow to manage the process I/O more efficiently. In particular, the inheritIO() set the subprocess standard I/O to be the same as those of the current Java process, and offer a behavior "equivalent" to the standard C library function system(). This is very great an usefull ! But there is another BIG difference between ProcessBuilder and the C library function system() : ProcessBuilder execute an application, and C system() evaluate a command-line using the OS's shell. So C's system() can use a lot of OS's specific syntax ($ENV or %ENV%, * ?, pipe, redirect, etc...) witch is incorrect on a ProcessBuilder (because this syntax is not interpreted but directly passed to the application). This is a common misunderstanding for Java's developer... My proposal simply consist to add a method that create a ProcessBuilder pre-filled with a shell command's line, by invoking the OS's shell ("/bin/sh" on Unixes, "command.com" on Win9x, "cmd.exe" on WinNT, etc. ? ) in order to evaluate a more complex command-line. A "basic" implementation can be like this : ====================================================================== /** * Create a new ProcessBuilder initialized to call an OS's * specific command-line. */ public static ProcessBuilder createShellFor(String commandLine) { String osName = System.getProperty("os.name"); if (osName.startsWith("Windows")) { if (osName.startsWith("Windows 95") || osName.startsWith("Windows 98") || osName.startsWith("Windows Me") ) { return new ProcessBuilder("command.com", "/C", commandLine); } return new ProcessBuilder("cmd.exe", "/C", commandLine); } return new ProcessBuilder("/bin/sh", "-c", commandLine); } ====================================================================== This method can be improved with more specific code depending on OS. And a "system()" method with a behavior really equivalent to the standard C library function system(), like this : ====================================================================== /** * Executes a command specified in 'commandLine' by calling * the OS shell program, and returns after the command has been completed. * @param commandLine The command-line to execute, using OS shell. * @return the exit value of the subprocess */ public static int system(String commandLine) throws IOException, InterruptedException { final Process process = createShellFor(commandLine).inheritIO().start(); try { return process.waitFor(); } finally { process.destroy(); } } ====================================================================== So, more complex and specific command-line can be used directly, like in lots of others languages... Thanks for reading, Fred
Hello, Sorry to revive this request, but I think this is as simple but very useful method that must be present on Java 7. No one have an opinion on this? Fred, Le 17 septembre 2009 09:16, Frédéric Martini <frederic.martini@gmail.com> a écrit :
Hello (before to start, sorry for my bad english)
I have seen in the last JDK's build that ProcessBuilder allow to manage the process I/O more efficiently. In particular, the inheritIO() set the subprocess standard I/O to be the same as those of the current Java process, and offer a behavior "equivalent" to the standard C library function system(). This is very great an usefull !
But there is another BIG difference between ProcessBuilder and the C library function system() : ProcessBuilder execute an application, and C system() evaluate a command-line using the OS's shell. So C's system() can use a lot of OS's specific syntax ($ENV or %ENV%, * ?, pipe, redirect, etc...) witch is incorrect on a ProcessBuilder (because this syntax is not interpreted but directly passed to the application).
This is a common misunderstanding for Java's developer...
My proposal simply consist to add a method that create a ProcessBuilder pre-filled with a shell command's line, by invoking the OS's shell ("/bin/sh" on Unixes, "command.com" on Win9x, "cmd.exe" on WinNT, etc. ? ) in order to evaluate a more complex command-line. A "basic" implementation can be like this :
======================================================================
/** * Create a new ProcessBuilder initialized to call an OS's * specific command-line. */ public static ProcessBuilder createShellFor(String commandLine) { String osName = System.getProperty("os.name"); if (osName.startsWith("Windows")) { if (osName.startsWith("Windows 95") || osName.startsWith("Windows 98") || osName.startsWith("Windows Me") ) { return new ProcessBuilder("command.com", "/C", commandLine); } return new ProcessBuilder("cmd.exe", "/C", commandLine); } return new ProcessBuilder("/bin/sh", "-c", commandLine); }
====================================================================== This method can be improved with more specific code depending on OS.
And a "system()" method with a behavior really equivalent to the standard C library function system(), like this :
======================================================================
/** * Executes a command specified in 'commandLine' by calling * the OS shell program, and returns after the command has been completed. * @param commandLine The command-line to execute, using OS shell. * @return the exit value of the subprocess */ public static int system(String commandLine) throws IOException, InterruptedException { final Process process = createShellFor(commandLine).inheritIO().start(); try { return process.waitFor(); } finally { process.destroy(); } }
======================================================================
So, more complex and specific command-line can be used directly, like in lots of others languages...
Thanks for reading, Fred
Il 15/10/2009 15:32, Frédéric Martini ha scritto:
Hello,
Sorry to revive this request, but I think this is as simple but very useful method that must be present on Java 7.
No one have an opinion on this?
Fred,
I'm not sure. In my opinion this is easy to do in application code using something similar to what you did or Runtime.exec, but doesn't fit into the core library. Also, in this implementation you are assuming lots of things that are not valid everywhere, like: The system is either Windows or Linux or Solaris (or some other "sane" unix variant), the system has /bin/sh, and it's possible to use it to execute process etc... I would not like much to see this in the standard library, especially in java.lang, as this thing is non portable by definition. Cheers, Mario -- Mario Torre, Software Developer, http://www.jroller.com/neugens/ aicas Allerton Interworks Computer Automated Systems GmbH Haid-und-Neu-Straße 18 * D-76131 Karlsruhe * Germany http://www.aicas.com * Tel: +49-721-663 968-44 pgp key: http://subkeys.pgp.net/ PGP Key ID: 80F240CF Fingerprint: BA39 9666 94EC 8B73 27FA FC7C 4086 63E3 80F2 40CF USt-Id: DE216375633, Handelsregister HRB 109481, AG Mannheim Geschäftsführer: Dr. James J. Hunt Please, support open standards: http://endsoftpatents.org/
Hi Frédéric, Thanks for your suggestion. The JDK has long had a culture of pushing people to write portable code, and so any facility that would make it easier to interact with the operating system in a non-portable way meets resistance. Another issue is that the "default" C system shell tends to become dated over time - there are often better command interpreters. Nevertheless, the existence of C "system" and the "shell" keyword arg to python's subprocess.Popen are strong arguments that the concept of a default shell is entrenched in the programmer community. Therefore, I support this proposal in principle. Would someone at Sun like to sponsor this API change? The spec probably needs a bit more work, so that readers will know that we're talking about e.g. /bin/sh without making that explicit. Martin 2009/9/17 Frédéric Martini <frederic.martini@gmail.com>:
Hello (before to start, sorry for my bad english)
I have seen in the last JDK's build that ProcessBuilder allow to manage the process I/O more efficiently. In particular, the inheritIO() set the subprocess standard I/O to be the same as those of the current Java process, and offer a behavior "equivalent" to the standard C library function system(). This is very great an usefull !
But there is another BIG difference between ProcessBuilder and the C library function system() : ProcessBuilder execute an application, and C system() evaluate a command-line using the OS's shell. So C's system() can use a lot of OS's specific syntax ($ENV or %ENV%, * ?, pipe, redirect, etc...) witch is incorrect on a ProcessBuilder (because this syntax is not interpreted but directly passed to the application).
This is a common misunderstanding for Java's developer...
My proposal simply consist to add a method that create a ProcessBuilder pre-filled with a shell command's line, by invoking the OS's shell ("/bin/sh" on Unixes, "command.com" on Win9x, "cmd.exe" on WinNT, etc. ? ) in order to evaluate a more complex command-line. A "basic" implementation can be like this :
======================================================================
/** * Create a new ProcessBuilder initialized to call an OS's * specific command-line. */ public static ProcessBuilder createShellFor(String commandLine) { String osName = System.getProperty("os.name"); if (osName.startsWith("Windows")) { if (osName.startsWith("Windows 95") || osName.startsWith("Windows 98") || osName.startsWith("Windows Me") ) { return new ProcessBuilder("command.com", "/C", commandLine); } return new ProcessBuilder("cmd.exe", "/C", commandLine); } return new ProcessBuilder("/bin/sh", "-c", commandLine); }
====================================================================== This method can be improved with more specific code depending on OS.
And a "system()" method with a behavior really equivalent to the standard C library function system(), like this :
======================================================================
/** * Executes a command specified in 'commandLine' by calling * the OS shell program, and returns after the command has been completed. * @param commandLine The command-line to execute, using OS shell. * @return the exit value of the subprocess */ public static int system(String commandLine) throws IOException, InterruptedException { final Process process = createShellFor(commandLine).inheritIO().start(); try { return process.waitFor(); } finally { process.destroy(); } }
======================================================================
So, more complex and specific command-line can be used directly, like in lots of others languages...
Thanks for reading, Fred
participants (3)
-
Frédéric Martini
-
Mario Torre
-
Martin Buchholz