Executing a native DOS command from a Java application - java

I am interested in executing the cmd.exe move command from a Java application.
I know how to invoke external processes from within Java. There are 100's of questions on this point in StackOverflow. What I can't figure out, is what the command line should look like.
For example, in a DOS window, this is the command I type:
move dirA dirB
and the directory dirA is moved to directory dirB. Exactly what I want done. For reasons that require far too much context, and will detract from the question, a pure java solution is not an option in the specific context I am concerned with. (Oh the joys of operating in an enormous and complex legacy systems!)
What is the external system command I invoke from java to do that? It seems like it should just be:
"cmd move dirA dirB"
However, that fails for me. I am familiar with this question, but it does not directly answer my question.

No guarantees but I suppose, that you need to prepend the command to run the Windows command shell cmd /c to the command you want to execute. The /c switch terminates the command shell after the desired command completes.
Try:
Runtime.getRuntime().exec("cmd /c move dirA dirB");
EDIT:
As Ian Roberts
have noticed in his comment below, it is also important to take into consideration situation when one or both of directories have spaces in their paths. It is thus much safer to use separate strings to form the finall command, i.e like below:
new ProcessBuilder("cmd", "/c", "move", pathToDirA, pathToDirB).start()

Related

Java Runtime OR Processbuilder OR Other

I'd like to know what the best alternative is for running command line executables from Java. The Target platforms for the commands are Windows 7(+) and Unix/Linux.
I have a class that currently uses Runtime.exec() along with the enhancements from the JavaWorld StreamGobbler article. It works about 90% of the time on both Windows and Unix. The other 10% of the time I need to extend the class and then fiddle with putting cmd.exe of /bin/sh in front of the command. I've also had to fiddle sometimes between using a single String that has command and arguments to splitting the command and args into a String[] array.
My latest is a new error/exception "java.lang.IllegalArgumentException: Executable name has embedded quote, split the arguments." My current Runtime.exec() class works fine in Eclipse running as a Java application, but once I build it and run from an actually command prompt, it fails with the above exception.
So now I'm reading that we should be using ProcessBuilder to do command line executables to the OS platform.
My question is, what is the best alternative? Runtime.exec(), ProcessBuilder, or some other option? Is there one option that will service both Windows and Unix/Linux? If not, which one works best with Windows? Which one works best with Unix/Linux?
tia, adym
Not sure how to give Bohemian credit, but I used ProcessBuilder...Solution is at :
Java - ProcessBuilder command arguments with spaces and double-quotes fails

Executing bash script with tilde in path

I am trying to execute in linux:
command[0] = "~/test/bin/runScript_sh";
Runtime.getRuntime().exec(command);
But get an exception
java.io.IOException: Cannot run program
error=2, No such file or directory
Probably because it can not evaluate tilde.
What can be done?
I would replace it myself.
if(path.s.substring(0,1).contains("~"))
path = path.replaceFirst("~",System.getProperty("user.home"));
Which gets you the string you want.
You can get the user's home directory with System.getProperty:
command[0] = System.getProperty("user.home") + "/test/bin/runScript_sh";
When you run a command at the shell command prompt, things like ~ expansion, quote handling, globbing, $variable expansion, input/output redirection and piping and son on are all handled by the shell ... before it asks the operating system to run the program(s) for you.
When you run a command using Runtime.exec, you have three choices:
write the command without any shell "funky stuff"
replicate what the shell would do in Java; e.g. replace leading tildes with the appropriate stuff1, or
use exec to launch a child shell to run the command; e.g.
Runtime.getRuntime().exec("/bin/sh", "-c", "~/test/bin/runScript_sh");
That is possibly overkill in a simple case like this. But if you are trying to do more complicated things then a child shell can really simplify things.
1 - In fact fully shell compatible handing of tildes is fairly complicated.
Items such as ~ and $HOME are shell expansions
You have to expand these items in your program and then replace them (hint: get them from the os properties, see this page)

Java option -XX:OnOutOfMemoryError does not work when called through exec in bash script

I have a java application and I want to run a script whenever it experiences and OutOfMemoryException
This works great:
$ java -server -XX:OnOutOfMemoryError="./oom_script %p" TestOOMClass
Unfortunately my application is run by a bash script in production. The script boils down to this:
cmd='java -server -XX:OnOutOfMemoryError="./oom_script %p" TestOOMClass'
##does a lot of checking and cmd building here
exec -a app ${cmd}
When run like this java never respects the double quotes and thinks %p is the class. how do I prevent this? I've tried double escaping but that doesn't work.
Since your program is run as a shell script, I would suggest putting this as the first line in your shell script after the shebang:
set -xv
Then, in the crontab, put 2>&1 at the end of the command line, so STDERR and STDOUT are merged. Crontab usually emails out the STDOUT of a command to root, so you can see what the output is. If not, then apend the following to the end of the command in your crontab:
> /somedir/output.$$ 2>&1
Make sure somedir exists, and after crontab runs your command, you'll see the verbose and debug output. Each line in your shell script will be displayed before it is executed -- both as written and as the shell actually interprets it.
The set -xv becomes very useful in debugging any sell script. There could be all sorts of environmental issues involved between the cronjob and the script running under your login. You might even find a shell issue. For example, crontab usually executes shell scripts in Bourne shell and you probably have Bash or Kornshell as your default shell. Whatever it is, you'll usually find out the issue very quickly when you turn on verbose/debug mode.
You don't even have to do this to the entire script. You can put set -xv anywhere in your script to turn on verbose/debug mode, and set +xv to turn it off.
I could make several pious high minded recommendations (use quotes, don't assume environment things, prefix your command line with "bash -c" to make sure you're using the right shell, etc.), but this would be guessing what could be wrong. In order to really debug this issue, I would need to see the machine, know the OS, see your entire shell script, and understand the entire environment. And, the first thing I would do is add set -xv in your shell script.
Quotes and escaping is an art. I would suggest you add echo ${cmd} before calling exec so you can see what it looks like then.
I would suggest using
cmd='java -server -XX:OnOutOfMemoryError=\\"./oom_script %p\\" TestOOMClass'
instead (untested). You need it to look like \" when being echoed.
an alternative i suggest (to bypass the problem, not solve it indeed) is to rung and bash script and access the $PPID:
PPID The process ID of the shell's parent. This variable is readonly.
then kill the process with that ID (please bare in mind that is an untested suggestion)

How to use mkdir and rmdir commands in a java program

I want to use system commands like mkdir and rmdir while running a java program.
How can I do that?
Why do you want to use the command line? FYI, there are built-in platform-independent File classes.
http://www.exampledepot.com/egs/java.io/deletefile.html
http://www.roseindia.net/java/beginners/java-create-directory.shtml
Make directory:
new File("dir path").mkdir();
Remove directory:
new File("dir path").delete();
'new File' here is a bit of a misnomer, it isn't actually creating the directory or a file. It's creating a Java resource hook which you can use to query or operate upon an existing filesystem resource, or create a new one at your request. Otherwise, use Runtime.getRuntime().exec("command line here") for using command line operations (not advised!!).
Edit: sorted out the problem the question poster was having:
String envp[] = new String[1];
envp[0] = "PATH=" + System.getProperty("java.library.path");
Runtime.getRuntime().exec("command line here", envp);
Note the insertion of envp into the exec(..) method call, which is basically the PATH variable from the environment.
As the other mentioned, you shouldn't do this for simple file management. But to have it mentioned: The Java API has a class called Runtime, that allows system calls... for example:
Runtime.getRuntime().exec("some_command");
The best is not to, but rather find the pure Java API function that does it. It is cleaner, easier to understand and much less error prone. It is also the only way to do Java that is write once run everywhere. Once you are calling shell commands, you are tied to that shell.
In your case you are looking for the java.io.File class, and specifically the mkdir and delete methods.
For reference of people stumbling onto this question and wondering why Runtime.getRuntime().exec("mkdir foo") doesn't work even when incorporating the environment as per Chris Dennett's answer, the most probable reason is that you don't have a program called "mkdir" on your system. While most Unix-like systems have a program of this name, it isn't absolutely necessary for them to have one, and Windows doesn't have one, because in both cases the shell interprets this command itself, rather than passing it to an external program.
To make it work, try ...exec ("cmd /c mkdir foo") for NT-family Windows (or "command /c mkdir foo" for Windows 95 family), or exec ("sh -c \"mkdir foo\"") for Unix.
The fact that there isn't a platform-independent way to do this is yet another reason to prefer the Java APIs for performing the task.
Hi Agree to the fact of not been platform independent but just for testing an app I had to use it.
The solution in my case for the
Runtime.getRuntime().exec("my_command_name") ;
for not working was i had to give the full path to where the batch/sh/executable file was
ie:
Runtime.getRuntime().exec("/d/temp/bin/mybatfile");

Java : how to determine disk space on Windows system prior to 1.6

I want to determine the available disk space on windows. I don't care that my code is not portable. I use this :
String[] command = {"dir",drive};
Process process = Runtime.getRuntime().exec(command);
InputStream result = process.getInputStream();
aiming to parse the result from a "dir C:" type of call, but the String I get from the command line call is as if I called dir with a /W option (not giving any information about file sizes or disk usage / free space). (Although when I launch dir C: directly from the command line, I get the expected result, so there is no dir particular setup on my system.) Trying to pass a token /-W or on any other option seems not to work : I just get the name of the folders/files contained in the drive, but no other information whatsoever.
Someone knows a fix / workaround ?
NOTE:
I can't go along the fsutil route, because fsutil does not work on network drives.
It sounds like your exec() is finding a program called "dir" somewhere in your path because with your String[] command as it is I would otherwise expect you to get an IOException (The system cannot find the file specified). The standard dir command is built into the cmd.exe Command Prompt and is not a standalone program you can execute in its own right.
To run the dir command built into cmd.exe you need to use the /c switch on cmd.exe which executes the specified command and then exits. So if you want to execute:
cmd /c dir
your arguments to pass to exec would be:
String[] command = { "cmd", "/c", "dir", drive };
If you don't care about portability, use the GetDiskFreeSpaceEx method from Win32 API. Wrap it using JNI, and viola!
Your Java code should look like:
public native long getFreeSpace(String driveName);
and the rest can be done through the example here. I think that while JNI has its performance problems, it is less likely to cause the amount of pain you'll endure by using the Process class....
Apache Commons has FileSystemUtils.freeSpaceKb() that will work cross platfrom etc etc

Categories

Resources