Apache Commons Exec 的 CommandLine

本文将介绍 Apache Commons Exec 中的 CommandLine 类的具体用法

在 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 对象。

构建命令行(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 类

CommandLine 对象有助于处理指定要执行的进程的命令行,应用程序可以将该类用于命令行。

addArgument 方法

该方法用来向当前命令行添加单个参数,方法签名如下:

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,即使参数中拥有空格也不会进行双引号/单引号处理。

addArguments 方法

该方法一次性向当前命令行添加多个参数,方法签名如下:

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 硬生生的把它们拆开了,这就是副作用。只需要给参数添加单引号/双引号。

setSubstitutionMap 方法

该方法用来给参数设置扩展变量,例如:

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

}
学习从来无捷径,循序渐进登高峰。 —— 高永祚
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号