在 Apache Commons Exec 中,CommandLine 是一个非常重要的对象,表示一个命令行(例如:cmd.exe /C ping www.hxstrive.com)。同时,也是 Executor.execute() 方法的必须参数。Executor 提供了如下几种 execute() 重载方法,如下:
// 启动异步执行的方法 int execute(CommandLine command) void execute(CommandLine command, ExecuteResultHandler handler) int execute(CommandLine command, Map<String,String> environment) void execute(CommandLine command, Map<String,String> environment, ExecuteResultHandler handler)
下面将介绍怎样去构建命令行 CommandLine 对象。
您有两种方法可以创建要执行的命令行,分别如下:
解析整个命令行字符串
逐步构建命令行
无论您使用哪种方法,commons-exec 都会在以下两种情况下更改您的命令行参数:
当可执行文件包含正斜杠或反斜杠时
当命令行参数包含未加引号的字符串时
以下可执行参数
./bin/vim
将在 Windows 下转换为
.\\bin\\vim
使用 Commons Exec 库解析命令行字符串很容易使用,但在处理复杂场景时可能会遇到问题。因此,此功能在 Ant Exec 任务中已被弃用。
让我们看几个你想坚持解析整个命令行字符串的例子。
在这里,我们要调用一个批处理文件(versionInfo.bat),其中包含路径中的空格。如下:
cmd.exe /C c:\was51\Web Sphere\AppServer\bin\versionInfo.bat
由于文件名中的空格,我们必须用单引号或双引号引用文件名,否则它会分解为两个命令行参数 c:\was51\Web 和 Sphere\AppServer\bin\versionInfo.bat。如下:
String line = "cmd.exe /C 'c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat'";
Java 代码如下:
import org.apache.commons.exec.CommandLine; /** * 验证参数中拥有空格时,CommandLine 会自动使用单双引号将参数括起来 * @author hxstrive.com 2021/12/23 */ public class CommandLineDemo1 { public static void main(String[] args) { // cmd.exe /C c:\was51\Web Sphere\AppServer\bin\versionInfo.bat CommandLine line = new CommandLine("cmd.exe"); line.addArgument("/C"); line.addArgument("c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat"); System.out.println(line); // 输出结果: // [cmd.exe, /C, "c:\was51\Web Sphere\AppServer\bin\versionInfo.bat"] } }
这是推荐的方法,也适用于预先引用(pre-quoted)的命令行参数。
现在我们想构建以下命令行:
runMemorySud.cmd 10 30 -XX:+UseParallelGC -XX:ParallelGCThreads=2
使用以下 Java 代码片段:
CommandLine cmdl = new CommandLine("runMemorySud.cmd"); cmdl.addArgument("10"); cmdl.addArgument("30"); cmdl.addArgument("-XX:+UseParallelGC"); cmdl.addArgument("-XX:ParallelGCThreads=2");
现在让我们看看在互联网某处找到的以下命令行:
dotnetfx.exe /q:a /c:"install.exe /l ""\Documents and Settings\myusername\Local Settings\Temp\netfx.log"" /q"
以下代码片段使用预先引用的参数和变量扩展构建命令行
File file = new File("/Documents and Settings/myusername/Local Settings/Temp/netfx.log"); Map map = new HashMap(); map.put("FILE", file); cmdl = new CommandLine("dotnetfx.exe"); cmdl.setSubstitutionMap(map); cmdl.addArgument("/q:a", false); cmdl.addArgument("/c:\"install.exe /l \"\"${FILE}\"\" /q\"", false);
CommandLine 对象有助于处理指定要执行的进程的命令行,应用程序可以将该类用于命令行。
该方法用来向当前命令行添加单个参数,方法签名如下:
CommandLineaddArgument(String argument) CommandLineaddArgument(String argument, boolean handleQuoting)
其中:
argument - 待添加的参数
handleQuoting - 指定是否给当前参数添加引号
示例:
import org.apache.commons.exec.CommandLine; /** * 验证 addArgument() 方法的第二个参数 handleQuoting 的含义 * @author hxstrive.com 2021/12/23 */ public class CommandLineDemo3 { public static void main(String[] args) { CommandLine cmdl = new CommandLine("runMemorySud.cmd"); cmdl.addArgument("-n 10"); cmdl.addArgument("-size 30"); cmdl.addArgument("-XX: +UseParallelGC", false); cmdl.addArgument("-XX: ParallelGCThreads=2", true); System.out.println(cmdl); // 输出结果: // [runMemorySud.cmd, "-n 10", "-size 30", -XX: +UseParallelGC, "-XX: ParallelGCThreads=2"] } }
上面代码中,四个参数中均拥有空格,默认情况下 Commons Exec 会使用双引号/单引号处理参数。如果我们将 addArgument() 参数的 handleQuoting 设置为 false,即使参数中拥有空格也不会进行双引号/单引号处理。
该方法一次性向当前命令行添加多个参数,方法签名如下:
CommandLineaddArguments(String addArguments) CommandLineaddArguments(String[] addArguments) CommandLineaddArguments(String[] addArguments, boolean handleQuoting) CommandLineaddArguments(String addArguments, boolean handleQuoting)
示例:
import org.apache.commons.exec.CommandLine; /** * 验证 addArguments() 方法一次性添加多个参数 * @author hxstrive.com 2021/12/23 */ public class CommandLineDemo5 { public static void main(String[] args) { CommandLine cmdl = new CommandLine("runMemorySud.cmd"); cmdl.addArguments("-n 10 -size 30 -XX: +UseParallelGC -XX: ParallelGCThreads=2"); System.out.println(cmdl); // 输出结果: // [runMemorySud.cmd, -n, 10, -size, 30, -XX:, +UseParallelGC, -XX:, ParallelGCThreads=2] CommandLine cmdl2 = new CommandLine("runMemorySud.cmd"); cmdl2.addArguments("'-n 10' '-size 30' '-XX: +UseParallelGC' '-XX: ParallelGCThreads=2'"); System.out.println(cmdl2); // 输出结果: // [runMemorySud.cmd, "-n 10", "-size 30", "-XX: +UseParallelGC", "-XX: ParallelGCThreads=2"] } }
上面代码中,如果参数包含空格,则默认将会拆分成多个参数。例如:-n 10(或-size 30、-XX: +UseParallelGC、-XX: ParallelGCThreads=2)均代表一个参数。然而输出结果为:
[runMemorySud.cmd, -n, 10, -size, 30, -XX:, +UseParallelGC, -XX:, ParallelGCThreads=2]
Commons Exec 硬生生的把它们拆开了,这就是副作用。只需要给参数添加单引号/双引号。
该方法用来给参数设置扩展变量,例如:
import org.apache.commons.exec.CommandLine; import java.io.File; import java.util.HashMap; import java.util.Map; /** * 验证 setSubstitutionMap() 方法一次性添加多个参数 * @author hxstrive.com 2021/12/23 */ public class CommandLineDemo6 { public static void main(String[] args) { File file = new File("/Documents and Settings/myusername/Local Settings/Temp/netfx.log"); Map map = new HashMap(); map.put("FILE", file); CommandLine cmdl = new CommandLine("dotnetfx.exe"); cmdl.setSubstitutionMap(map); cmdl.addArgument("/q:a", false); cmdl.addArgument("/c:\"install.exe /l \"\"${FILE}\"\" /q\"", false); System.out.println(cmdl); // 输出结果: // [dotnetfx.exe, /q:a, /c:"install.exe /l ""D:\Documents and Settings\myusername\Local Settings\Temp\netfx.log"" /q"] } }