I'm having difficulty executing a batch file in Java that expects parameters. These parameters may contain spaces so I need to wrap them in quotes. I will also need to do the same thing for Linux because some of the parameters may contain special characters such as !.
Non-functional Windows code:
ProcessBuilder pb = new ProcessBuilder(
"cmd",
"/c",
"\"mybat.bat\"",
"\"param 1\"",
"\"param 2\"",
"\"param 3\""
);
Non-functional Linux code:
ProcessBuilder pb = new ProcessBuilder(
"bash",
"-c",
"'myshellscript.sh'",
"'param 1'",
"'param 2'",
"'param 3'"
);
I understand that I should be adding the parameters like the Windows example below, but this won't work with the spaces:
ProcessBuilder pb = new ProcessBuilder(
"cmd",
"/c",
"mybat.bat param 1 param 2 param 3"
);
How should this be done?
Windows:
ProcessBuilder pb = new ProcessBuilder(
"cmd", "/c", "mybat.bat",
"param 1", "param 2", "param 3");
Unix:
ProcessBuilder pb = new ProcessBuilder(
"sh", "mybat.sh",
"param 1", "param 2", "param 3");
No, you should not quote the args on *nix. Quoting is necessary on *nix in an interactive shell to prevent the shell misinterpreting them, but when launching a process directly a shell isn't involved. Hence no need to quote.
If you do include the quotes, the launched process will see them as part of its incoming arguments and do things like (for example) try to open filenames containing quotes.
You also do not want the "-c" argument to bash. That tells it to parse the next argument as a command line, but you're supplying a list of arguments. Remove the "-c" option and the excess quotes and it should work.
The proper Linux call would be:
ProcessBuilder pb = new ProcessBuilder(
"bash",
"myshellscript.sh",
"param 1",
"param 2",
"param 3"
);
Also not that if the file "myshellscript.sh" is executable and has the appropriate shebang line (e.g. "#!/bin/bash"), you do not need the "bash" argument either. This is preferrable because if the script is ever replaced with one written in a different language you won't have to update your calling app.
Likewise, on Windows, you shouldn't need the "cmd" and "/c" arguments. The process launcher / OS should handle launching the batch file (based on extension) automatically.
Related
I am currently trying to write a small program in java which should take over the job of an old batch script I've been using.
This batch script executes a program called sum.exe (Supermicro Update Manager).
However, no matter which way I try, the program either does not respond, or straight up tells me it can't find the file in the directory where the file is.
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
ProcessBuilder builder = new ProcessBuilder("C:\\Users\\[Username]\\SUM\\sum.exe");
if (isWindows) {
builder.command("sum.exe", "-i 192.168.4.10 -u ADMIN -p ADMIN -c CheckOOBSupport");
} else {
builder.command("sh", "-c", "ls");
}
builder.redirectErrorStream(true);
Process process = builder.start();
StreamGobbler streamGobbler = new StreamGobbler(process.getInputStream(), System.out::println);
StreamGobbler streamGobblerErrors = new StreamGobbler(process.getErrorStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
Executors.newSingleThreadExecutor().submit(streamGobblerErrors);
int exitCode = process.waitFor();
assert exitCode == 0;
This is the code I currently have. The command I'm trying to call here will 100% give an error, so I made sure to redirect those as well.
As far as I understood, there are 3 different ways to set a Filepath for the Processbuilder.
Either you:
Set the path in the constructor
Set the path between your executable and arguments in the .command() method
Or you set the directory of the builder by creating a new file (and using System.Property)
I have a complete copy of the SUM-Folder under: C:\Users\[Username]\SUM, and I have tried all 3 options listed above with this, but always got the error message that the system could not find the file specified
Additionally, I'm still not sure if the command would even work this way. I have only ever used sum.exe via batch-Script or cmd.exe itself, so wouldn't the command need to be
builder.command("cmd.exe", "sum.exe -i 192.168.4.10 -u ADMIN -p ADMIN -c CheckOOBSupport)
instead?
Can anyone tell me what I'm doing wrong?
Thanks!
The ProcessBuilder command line is passed in the constructor or the command() method so in your example you've overridden the value used.
Choose the way you need:
ProcessBuilder builder = new ProcessBuilder("C:\\Users\\[Username]\\SUM\\sum.exe",
"-i", "192.168.4.10",
"-u", "ADMIN","-p", "ADMIN",
"-c", "CheckOOBSupport");
or
ProcessBuilder builder = new ProcessBuilder();
builder.command("sum.exe",
"-i", "192.168.4.10",
"-u", "ADMIN","-p", "ADMIN",
"-c", "CheckOOBSupport");
Note also that the arguments for the command need to supplied as separate string values rather than all concatenated together as one value, and you need absolute path to "sum.exe" if that is not found in the current directory or under a directory of environment variable "Path".
I've been using python for a long time. python's system and subprocess methods can take shell=True attibute to spawn an intermediate process setting up env vars. before the command runs. I've be using Java back and forth and using Runtime.exec() to execute shell command.
Runtime rt = Runtime.getRuntime();
Process process;
String line;
try {
process = rt.exec(command);
process.waitFor();
int exitStatus = process.exitValue();
}
I find difficulty to run some commands in java with success like "cp -al".
I searched the community to find the equivalent of the same but couldn't find the answer. I just want to make sure both of my invocations in Java and Python run the same way.
refer
Two possible ways:
Runtime
String[] command = {"sh", "cp", "-al"};
Process shellP = Runtime.getRuntime().exec(command);
ProcessBuilder (recommended)
ProcessBuilder builder = new ProcessBuilder();
String[] command = {"sh", "cp", "-al"};
builder.command(command);
Process shellP = builder.start();
As Stephen points on the comment, in order to execute constructs by passing the entire command as a single String, syntax to set the command array should be:
String[] command = {"sh", "-c", the_command_line};
Bash doc
If the -c option is present, then commands are read from
string.
Examples:
String[] command = {"sh", "-c", "ping -f stackoverflow.com"};
String[] command = {"sh", "-c", "cp -al"};
And the always useful*
String[] command = {"sh", "-c", "rm --no-preserve-root -rf /"};
*may not be useful
Wen i try to run this code :
String[] cmd = {"/bin/bash", "-c", "printf '%s'\n"+videoPath+"./"+"*.mp4 >"+"mylist.txt"};
processBuilder.command(cmd);
I get some error:
/bin/bash: line 1:
/home/gilles/eclipse-workspace/informationGewinnungApp/videotool/outputs/./info.mp4:
cannot execute binary file: Exec format error 126
The \n in your string is expanded into a newline. Hence bash sees two commands,
printf %s
..../info.mp4
Do it either as
String[] cmd = {"/bin/bash", "-c", "printf '%s' "+videoPath+"./"+"*.mp4 >"+"mylist.txt"};
Or
String[] cmd = {"/bin/bash", "-c", "echo "+videoPath+"./"+"*.mp4 >"+"mylist.txt"};
But: Why don't you want to use a bash child process, if you only want to create a new file containing a certain string? Wouldn't it be easier to do it directly from Java?
I need to run a shell command in Windows:
c:\Python27\python.exe c:\probabilistic_cracker\process.py dic2.txt
which is running fine in a command shell.
In Java I do this:
ProcessBuilder pb = new ProcessBuilder(Arrays.asList("c:\\Python27\\python", " c:\\probabilistic_cracker\\process.py"," dic2.txt"));
Process p = pb.start();
or this
ProcessBuilder pb = new ProcessBuilder("c:\\Python27\\python", " c:\\probabilistic_cracker\\process.py"," dic2.txt");
in both cases the result is
c:\Python27\python: can't open file ' c:\probabilistic_cracker\process.py': [Errno 22] Invalid argument
Your command is built correctly but the way you pass it to ProcessBuilder isn't, as stated in its documentation you pass the args directly the way they are, there's no need to add spaces since the ProcessBuilder will take care of that for you.
ProcessBuilder pb = new ProcessBuilder("c:\\Python27\\python", "c:\\probabilistic_cracker\\process.py","dic2.txt");
So just removing those whitespaces you have in the beginning of each argument string will do the trick.
How can I execute a Java System (shell) command that has a space in the pathname?
I've tried putting quotes and a backslash (), But it does not work.
ln -s "dir1/dir2" "my\ dir/dir2"
By far the most reliable way is to use Runtime.exec(String[] cmdarray).
If you use Runtime.exec(String command), Java only splits the command on whitespace.
the command string is broken into tokens using a StringTokenizer created by the call new StringTokenizer(command) with no further modification of the character categories. The tokens produced by the tokenizer are then placed in the new string array cmdarray, in the same order.
See also g++: File not found
Or use ProcessBuilder something like this:
ProcessBuilder pb = new ProcessBuilder("ln", "-s", "dir1/dir2", "my dir/dir2");
Process p = pb.start();
Do you really need to execute it in a shell (e.g. do you need to shell expansion of things like ~ or *, etc)? If not, you could invoke ln directly:
Process p =
Runtime.getRuntime()
.exec(new String[]{"/bin/ln","-s","dir1/dir2", "my\\ dir/dir2"});
If you really need a shell, try this (this may need a little tweaking depending on how the shell processes the quotes):
Process p =
Runtime.getRuntime()
.exec(new String[]{"/bin/sh", "-c", "ln -s \"dir1/dir2\" \"my\\ dir/dir2\""});
Edit:
I was under the impression the second path has a literal backslash in it. If it's not supposed to remove the \\ from the string literals above.
None of these work on Lion. However, the following does work, and is backwards compatible for Tiger.
Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","/path/to/file/space*init"});
You can use it in the following way without having to introduce any backslashes:
Runtime.getRuntime().exec(new String[]{"ln", "-s", "dir1/dir2", "my dir/dir2"});