在 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"]
}
}