(as others said) For simple commands, you can just do, eg:
Runtime.getRuntime().exec("cmd /c mkdir H:\\test\\BBB");
(cmd /c
is likely needed)
However, for some complex commands, you may need to do a double cmd.exe /c cmd.exe /c
,
otherwise (if you use only 1) the cmd gets silently dropped,
((or if you dont use /c
or use some weird /c
cmd
combination pattern, cmd may freeze)),
idk why.
((How I discorve it? -- I couldnt get it work & tried mutiple time; one time accidentally duplicated the cmd & ran it & found it.))
@eg::
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class T1 {
static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
public static void main(String[] args) throws InterruptedException, IOException {
Process process;
System.out.println("---"); // creates a folder `BBB`
Runtime.getRuntime().exec("cmd /c mkdir H:\\test\\BBB");
// System.out.println("---");
// idk how to do `cd`
System.out.println("---"); // list file & folder in C:\
process = Runtime.getRuntime().exec("cmd.exe /c dir C:\\");
System.out.println(convertStreamToString(process.getInputStream()));
System.out.println("---"); // echo
process = Runtime.getRuntime().exec("cmd.exe /c echo \"Some Line\"");
System.out.println(convertStreamToString(process.getInputStream()));
// @atten: notice the double `cmd.exe /c cmd.exe /c `
// -- idk why must double - otherwise this wont execute
System.out.println("---"); // uses mysqldump to do something
process = Runtime.getRuntime().exec("cmd.exe /c cmd.exe /c \"C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysqldump.exe\" -u root -pmysql db_drawandchat_01 > \"H:\\DrawAndChatApp_db\\DrawAndChat_20230503_0134_03326.sql\"");
}
// Output::
//
// ---
// ---
// Volume in drive C has no label.
// Volume Serial Number is 2C83-063F
//
// Directory of C:\
//
// 2019/06/29 11:56 <DIR> Intel
// 2022/04/18 06:07 <DIR> log
// 2019/12/07 17:14 <DIR> PerfLogs
// 2023/04/22 01:13 <DIR> Program Files
// 2023/04/08 21:27 <DIR> Program Files (x86)
// 2020/12/08 00:15 <DIR> Untitled
// 2021/04/23 04:57 <DIR> Users
// 2023/04/25 09:33 <DIR> Windows
// 0 File(s) 0 bytes
// 8 Dir(s) 3,268,296,704 bytes free
//
// ---
// "Some Line"
//
// ---
}
update
base on my experience
ProcessBuilder
with array of String as args
is a much better choice.
@note::
use array of String as args
, dont use a whole String
otherwise the parsing is likely to be wrong.
CreateProcess error=2, The system cannot find the file specified
remove unnecessary double quotes (eg: the ones around a path of a exec)
(since you are using array, the space_in_path cmd problem is kinda eliminated // actually, not really, see update below -> still use [a double cmd.exe /c cmd.exe /c
]).
Java - ProcessBuilder command arguments with spaces and double-quotes fails
the array is separated base on the "exec & flag & arg & path"
-- normally, wherever you have a space, you separate there (though, not on the paths)
- sometimes you dont separate the flag and arg (if there is no space between them), eg:
-pPASSWORD
@eg:: [String Cmd to Array Cmd in ProcessBuilder]
(following code worked before, but didnt test after some minor modifications)
public class T1 {
public static void main(String[] args) throws InterruptedException, IOException {
String cmdStr_loadFile = "cmd.exe /c cmd.exe /c "
+ "\"C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysql.exe\" "
+ "-u root "
+ "-pmysql "
+ "--database db_drawandchat_02 "
+ "< "
+ "\"H:\\DrawAndChatApp_db\\DrawAndChat_test.sql\"";
ArrayList<String> cmdArr_loadFile = new ArrayList<>(Arrays.asList("cmd", "/c",
"C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysql.exe",
"-u", "root",
"-pmysql",
"--database", "db_drawandchat_02",
"<",
"H:\\DrawAndChatApp_db\\DrawAndChat_test.sql"));
try {
// Process process = Runtime.getRuntime().exec(cmdStr_loadFile);
ProcessBuilder processBuilder = new ProcessBuilder(cmdArr_loadFile);
// processBuilder.directory(new File("H:/"));
processBuilder.redirectOutput(Redirect.INHERIT);
processBuilder.redirectError(Redirect.INHERIT);
// processBuilder.redirectInput(Redirect.INHERIT);
Process process = processBuilder.start();
try {
process.waitFor(20, TimeUnit.SECONDS);
// System.out.println(StringUtil.convertStreamToString(process.getInputStream()));
} catch (InterruptedException e) {
throw new Error(e);
}
} catch (IOException e) {
throw new Error(e);
}
}
}
update
The use of >"a double cmd.exe /c cmd.exe /c
"
is also working in the case of >"ProcessBuilder
with array of String as args
"
Especially when you have space in your path -- both executable path && file path arg
@eg::
ArrayList<String> cmdArr_saveFile = new ArrayList<>(
Arrays.asList("cmd", "/c", "cmd", "/c",
"C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysqldump.exe",
"-u", "root",
"-pmysql",
"db_drawandchat_01",
">",
"H:\\DrawAndChatApp_db\\DrawAndChat test2.sql"));