Runtime.getRuntime().exec(new String[] {
"cmd",
"/c",
"start",
"cd",
"M:\\MandNDrives\\mwallace\\PROPHET\\PROPHET\\Prophet2012"
"prpht0912" //shortcut to prpht0912.exe
"eorinput" // eorinput.ind, input sheet that prpht0912.exe processes
Opens a command prompt to the dir I need.
To execute the program contained in that folder, I then need to execute "prpht0912 eorinput" from the command prompt like:
M:\MandNDrives\mwallace\PROPHET\PROPHET\Prophet2012>prpht0912 eorinput
However the space in the entry returns an error in the prompt: "The system cannot find the path specified"
It isn't possible to execute two commands via the command line in a single invocation of cmd.exe: cmd.exe /c is followed by a single command, and another /c afterwards would be interpreted as a parameter to that command.
Furthermore, invoking it twice won't get you what you want either, as changes of directory are forgotten when the process exits, so the second invocation would be run in the default working directory of the Java process, not the directory you changed to with your first invocation.
Also, it is unfortunate, but Java doesn't provide a way to change the current working directory of its own process.
As far as I can see it, you have two options:
Make sure your Java program is started with the working directory set to the one you need your child program to run in
Invoke a single .bat file that contains both of the commands you need to run.
To Execute the following command
M:\MandNDrives\mwallace\PROPHET\PROPHET\Prophet2012>prpht0912 eorinput
You need the following
String[] commands = new String[] { "cmd", "/c", "M:\\MandNDrives\\mwallace\\PROPHET\\PROPHET\\Prophet2012\\prpht0912.exe eorinput" };
Runtime.getRuntime().exec(commands);
Note**
When you pass an array, ProcessBuilder would consider only the first element as program and remaining as arguments for that program.
String prog = cmdarray[0];
Related
I'm having the next error when execute a cmd command using Java. I'm working in a mac laptop. This is my code:
private static String exportContainerFromImage(String container) {
//docker export mysql_dummy > ~/Documents/mysql_dummy.tar
String errorMessage = "";
String[] cmdArgs =
{"docker export mysql_dummy > ~/Documents/mysql_dummy.tar", "bash"};
Process process = Runtime.getRuntime().exec(cmdArgs);
}
But I'm getting the error, error=2, No such file or directory, if I execute the command directly on the terminal it runs successfully, I tried also changing the directory to ~\\Documents\\mysql_dummy.tar and got the same result.
But if I run the command with the arguments:
{"docker create -ti --name mysql_dummy mysql", "bash"};
It runs properly
Any ideas?
You're conflating 'shell magic' with 'an OS'. Also, you seem to be wildly confused about what the array form of cmdArgs does, because you've tagged a bash in there at the end. That array is supposed to contain the executable's full path at arr[0], and all arguments at arr[1] and up. docker create -ti ... is clearly not a filename, and bash is clearly not an argument.
Shell magic?
If you type:
docker create -ti --name mysql_dummy mysql
on the command line, bash (or cmd.exe if on windows, or whatever shell you are using) reads it and does a whole bunch of replacement magic and parsing on this. It's the shell that does this, not the OS, and java's processbuilder stuff is not a shell and therefore isn't going to do all that. What you're attempting to do? Run that entire line as if it's a single file name that is executable which it clearly isn't.
This is all shell magic - all things that you CANNOT do with exec. Fortunately, java is a programming language, so you can do all these things by, well, programming it.
Parsing out params by splitting on whitespace.
quoting to avoid that splitting, but then removing the quotes.
Treating ~ as a ref to a homedir.
Replacing * and ? in filename paths.
Variable substitution
Setting up redirects with > somefile.txt or 2> /dev/null or < file.in or whatnot.
You must do those things.
In addition, exec cannot be used to this, period. As usual, the only non-problematic way to run processes is to always use ProcessBuilder, no exceptions. Consider runtime.exec a known-broken method you must never call.
ProcessBuilder lets you redirect the output.
String[] cmdArgs = {
"/bin/docker" // note, FULL PATH!
"export",
"mysql_dummy"
};
File out = new File(System.getProperty("user.home"), "Documents/mysql_dummy.tar");
ProcessBuilder pb = new ProcessBuilder(cmdArgs);
pb.redirectOutput(new File(out));
pb.start();
That does what you want, presumably.
The alternative is to make a script (script.sh or script.bat) and then start bash or cmd.exe and ask it to run that script.
String[] args = { "/bin/bash", "-c", "/fully/qualified/path/to/the/script.sh" }
and then exec that. Now you can pile *.txt, > foobar.txt, ~/homediref, and all the other shellisms in that script as much as you like.
Overall #rzwiterloot's answer is good, but there are some alternatives it leaves out.
First, what I would consider the best solution to this problem: the -o option to docker export.
"docker", "export", "mysql_dummy", "-o", "Documents/mysql_dummy.tar"
Ignoring ~/ here, this set of command and arguments will achieve the same thing as ... > Documents/mysql_dummy.tar but doesn't rely on the shell for the redirection; docker export is perfectly capable of handling that operation itself.
Second, if you wanted to run a shell command from the program, you could. I would not recommend this. But in certain circumstances it might make sense.
The alternative is to make a script
You don't have to put the command in a separate file. Actually this is one inaccuracy in #rzwiterloot's answer; -c allows you to pass command(s) to bash, not the path to a file containing commands.
"bash", "-c", "docker export mysql_dummy > ~/Documents/mysql_dummy.tar"
However, I'd recommend you avoid invoking shells from any program you write. They're quirky and esoteric and there's almost always a simpler way to achieve what you want, such as docker export's -o optiopn, in this case.
For educational purpouses I am asked to use Java to call the execution of a .bat trough cmd.
As a starting point I did this little code, that for what I know should work, but executing the class does nothing, while running the .bat works as expected.
Java:
Runtime.getRuntime().exec("cmd /c start myDir.bat");
Content of myDir.bat (which is located in the same folder of the Java class):
dir > file_list.txt
Double click on the .bat generates and fills the file.
you can just execute : Runtime.getRuntime().exec("myDir.bat");
or provide absolutePath to your bat file.
You can also get OUTPUT and OUPUT ERROR from myDir.bat with java Thread.
If you are more than one parameter, you put an array string on exec method, example:
String[] p = {"cmd","/c","start","myDir.bat"};
Runtime.getRuntime().exec(p);
I'm trying to run cmder.exe from a java application. I'm using the java ProcessBuilder class and it works great with cmd.exe, but never with cmder.exe.
This is my code:
command = "cd C:\\Users\\fxxx\\Documents\\plt 3.0\\git\\xxx-estatic";
ProcessBuilder builder = new ProcessBuilder("C:\\PLT 3.0\\abc\\cmder_mini\\cmder.exe", "/start", command);
I want to open the cmder command prompt and run a "cd" command. Cmder.exe is actually launched, but I get the "file name, directory name or volume label syntax is incorrect" error message and my command (cd...) is never executed.
Again, things work perfectly if I use cmd.exe.
Does someone know how to effectively run cmder.exe from a java application?
Thanks a lot.
RTFM!
Assuming that you use that cmder.exe, the doc states:
Cmder.exe Command Line Arguments
Argument Description
/C [user_root_path] Individual user Cmder root folder. Example: %userprofile%\cmder_config
/SINGLE Start Cmder is single mode.
/START [start_path] Folder path to start in.
/TASK [task_name] Task to start after launch.
That means that your code should be:
path = "cd C:\\Users\\fxxx\\Documents\\plt 3.0\\git\\xxx-estatic";
ProcessBuilder builder = new ProcessBuilder("C:\\PLT 3.0\\abc\\cmder_mini\\cmder.exe", "/start", path);
I am running a batch (ScanProject.bat) file using java by following code
Process p= Runtime.getRuntime().exec("cmd /c start /wait ScanProject.bat "+ BaseProjDir+"\\"+jo.getString("Name")+" "+st.nextToken());
System.out.println("Exit value : "+p.waitFor());
And following is the batch file code :-
%2:
cd %1
ant -f ..\antbuild.xml analyse
exit
Batch file run successfully but problem is command prompt window do not closes automatically and hence Process do not terminated automatically and my program wait for infinite time to complete this process.Please suggest me any technique so that cmd exit after running ant -f ..\antbuild.xml analyse command.
Thanks.
cd /D "Full path of directory" or pushd "Full path of directory" with popd before exit is better to switch the current directory to any directory on any drive (cd and pushd/popd) or even to a network share (just pushd/popd). Run in a command prompt window cd /? and pushd /? for details.
cmd /C starts a new Windows command process with closing the process automatically after last command was executed. Run in a command prompt window cmd /? for details on options of Windows command interpreter.
start is a command to start a new Windows command process or a GUI/hybrid application in a separate process.
So what you do here is starting a new Windows command process which starts a new Windows command process.
Running in a command prompt window start /? outputs the help for this command. start interprets often the first double quoted string as title string for the new command process. This causes often troubles on command lines with at least 1 double quoted string. Therefore usage of start requires often an explicit definition of a title string in double quotes as first argument for start which can be even an empty string, i.e. simply "" as first argument after start.
As it can be read after running exit /? in a command prompt window, this command without /B always exits the current Windows command process immediately. So when ant.exe finished, the command process in which the batch file was processed is definitely terminated.
I'm having no experience on Java development, but in my point of view it should be enough to use the following execution command which does not need a batch file at all.
The Java code line
Process p= Runtime.getRuntime().exec("cmd.exe /C cd /D \"" + jo.getString("Name") + "\" && ant.exe -f ..\\antbuild.xml analyse");
should be enough to
start a new Windows command process,
set the current directory within this command process to the drive and directory specified by jo.getString("Name") which of course must return a directory path with drive letter and using backslashes as directory separators, and on success
execute ant in this directory with the specified parameters
with terminating the Windows command process automatically after console application ant.exe finished if ant.exe is a console application.
I'm not sure if cmd.exe /C is needed at all.
I suggest to test this command first manually from within a command prompt window. Then use it in the Java application if really working and producing the expected result. And finally I would further test if cmd.exe /C is needed at all in Java code.
See Single line with multiple commands using Windows batch file for details about the operator && to run a command after previous command was successful. And see also Why do not all started applications save the wanted information in the text files as expected? for an explanation of console / GUI / hybrid application.
NOTE: There is also Java Runtime method exec(String[] cmdarray, String[] envp, File dir) to execute a command like ant.exe with its parameters -f and ..\antbuild.xml and analyse in the directory defined with third parameter which might be better for this task.
Swap out exit for taskkill, assuming you do not have any other cmd processes running. Not very graceful but it will get the job done.
%2:
cd %1
ant -f ..\antbuild.xml analyse
taskkill /im cmd.exe
I am trying to accomplish two things:
I am running cygwin on Windows7 to execute my unix shell commands and I need to automate the process by writing a Java app. I already know how to use the windows shell through Java using the 'Process class' and Runtime.getRuntime().exec("cmd /c dir"). I need to be able to do the same with unix commands: i.e.: ls -la and so forth. What should I look into?
Is there a way to remember a shell's state?
explanation: when I use: Runtime.getRuntime().exec("cmd /c dir"), I always get a listing of my home directory. If I do Runtime.getRuntime().exec("cmd /c cd <some-folder>") and then do Runtime.getRuntime().exec("cmd /c dir") again, I will still get the listing of my home folder. Is there a way to tell the process to remember its state, like a regular shell would?
It seems that the bash command line proposed by PaĆlo does not work:
C:\cygwin\bin>bash -c ls -la
-la: ls: command not found
I am having trouble figuring out the technicalities.
This is my code:
p = Runtime.getRuntime().exec("C:\\cygwin\\bin\\bash.exe -c ls -la");
reader2 = new BufferedReader(new InputStreamReader(p.getInputStream()));
line = reader2.readLine();
line ends up having a null value.
I added this to my .bash_profile:
#BASH
export BASH_HOME=/cygdrive/c/cygwin
export PATH=$BASH_HOME/bin:$PATH
I added the following as well:
System Properties -> advanced -> Environment variables -> user variebales -> variable: BASH, value: c:\cygwin\bin
Still nothing...
However, if I execute this instead, it works!
p = Runtime.getRuntime().exec("c:\\cygwin\\bin\\ls -la ~/\"Eclipse_Workspace/RenameScript/files copy\"");
1. Calling unix commands:
You simply need to call your unix shell (e.g. the bash delivered with cygwin) instead of cmd.
bash -c "ls -la"
should do. Of course, if your command is an external program, you could simply call it directly:
ls -la
When starting this from Java, it is best to use the variant which takes a string array, as then
you don't have Java let it parse to see where the arguments start and stop:
Process p =
Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe",
"-c", "ls -la"},
new String[]{"PATH=/cygdrive/c/cygwin/bin"});
The error message in your example (ls: command not found) seems to show that your bash can't find the ls command. Maybe you need to put it into the PATH variable (see above for a way to do this from Java).
Maybe instead of /cygdrive/c/cygwin/bin, the right directory name would be /usr/bin.
(Everything is a bit complicated here by having to bridge between Unix and Windows
conventions everywhere.)
The simple ls command can be called like this:
Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\ls.exe", "-la"});
2. Invoking multiple commands:
There are basically two ways of invoking multiple commands in one shell:
passing them all at once to the shell; or
passing them interactively to the shell.
For the first way, simply give multiple commands as argument to the -c option, separated by ; or \n (a newline), like this:
bash -c "cd /bin/ ; ls -la"
or from Java (adapting the example above):
Process p =
Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe",
"-c", "cd /bin/; ls -la"},
new String[]{"PATH=/cygdrive/c/cygwin/bin"});
Here the shell will parse the command line as, and execute it as a script. If it contains multiple commands, they will all be executed, if the shell does not somehow exit before for some reason (like an exit command). (I'm not sure if the Windows cmd does work in a similar way. Please test and report.)
Instead of passing the bash (or cmd or whatever shell you are using) the commands on the
command line, you can pass them via the Process' input stream.
A shell started in "input mode" (e.g. one which got neither the -c option nor a shell script file argument) will read input from the stream, and interpret the first line as a command (or several ones).
Then it will execute this command. The command itself might read more input from the stream, if it wants.
Then the shell will read the next line, interpret it as a command, and execute.
(In some cases the shell has to read more than one line, for example for long strings or composed commands like if or loops.)
This will go on until either the end of the stream (e.g. stream.close() at your side) or executing an explicit exit command (or some other reasons to exit).
Here would be an example for this:
Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe", "-s"});
InputStream outStream = p.getInputStream(); // normal output of the shell
InputStream errStream = p.getInputStream(); // error output of the shell
// TODO: start separate threads to read these streams
PrintStream ps = new PrintStream(p.getOutputStream());
ps.println("cd /bin/");
ps.println("ls -la");
ps.println("exit");
ps.close();
You do not need cygwin here. There are several pure Java libraries implementing SSH protocol. Use them. BTW they will solve your second problem. You will open session and execute command withing the same session, so the shell state will be preserved automatically.
One example would be JSch.