Java命令执行操作

在 Java 中可用于执行系统命令的方式有三种,分别是java.lang.Runtimejava.lang.ProcessBuilder以及java.lang.UNIXProcess/ProcessImpl。这三种方式都是 JDK 原生提供的,并不需要再额外引入

一. java.lang.Runtime 执行命令

是 java.lang 中的一个类,主要是与操作系统交互执行操作命令。

而在 java.lang.Runtime 中我们主要关注 exec() 方法,使用该方法执行具体的命令,而执行 exec() 方法有以下六种重载形式,可以传入不同的数据类型的参数

方法 中文释义(非标准)
exec(String[] cmdarray) 在单独的进程中执行 指定的命令和参数。
exec(String command) 在单独的进程中执行 指定的字符串命令
exec(String command, String[] envp, File dir) 在具有指定环境和工作目录的单独进程中执行指定的字符串命令。
exec(String command, String[] envp) 在具有指定环境的单独进程中执行指定的字符串命令
exec(String[] cmdarray, String[] envp) 在具有指定环境的单 独进程中执行指定的命令和参数。
exec(String[] cmdarray, String[] envp, File dir) 在具有指定环境和工作目录的单独进程中执行指定的命令和参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.io.*;
import java.nio.charset.Charset;

public class ExecRuntime {
public static void main(String[] args) throws Exception {
String command1 = "cmd /c whoami";
//windows环境下执行
String[] command2 = {"powershell","/c","ping www.baidu.com"};
//String[] command2 = {"cmd","/c", "py","-3", "C:\\Users\\powerful\\Desktop\\dirsearch-0.4.2\\dirsearch.py", "-u", "https://www.baidu.com", "-e *"};
//Linux环境下执行,也可以是bash,
//String[] command3 = {"/bin/sh", "/root/xxx.sh", "xxx.sh所需的参数"};
//exec执行字符串命令
cmdstring(command1);
//exec以数组方式接受多个参数并执行
cmdarray(command2);
}
//exec执行 字符串 命令
private static void cmdstring(String command) throws IOException {
String line = null;
Process process = Runtime.getRuntime().exec(command);
//使用BufferedReader设置编码解决执行命令响应中文乱码问题
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("GBK")));
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
//exec以 数组方式 接受多个参数并执行
private static void cmdarray(String[] command) throws IOException {
String line = null;
Process process = Runtime.getRuntime().exec(command);
//使用BufferedReader设置编码解决执行命令响应中文乱码问题
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("GBK")));
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
}

本质上调用的是 ProcessBuilder 方法:

二. java.lang.ProcessBuilder 执行命令

在上面介绍了java.lang。java.lang.Runtime是其中的一个API。而 java.lang.ProcessBuilder 也是java.lang中的一个API。该类主要用于创建操作系统进程

2.1 command() 方法

command() 方法主要用于设置要执行的命令

command() 方法传参有两种方式,一种是可变的字符串(简单说就是可以传入普通字符串,或者字符串数组),另一种是字符串列表

1
2
3
//简易示例代码
ProcessBuilder p = new ProcessBuilder();
p.command("calc");

2.2 start() 方法

使用 start() 方法可以创建一个新的具有命令,或环境,或工作目录,或输入来源,或标准输出和标准错误输出的目标,或 redirectErrorStream 属性的进程。

新进程中调用的命令和参数有 command() 方法设置,工作目录将由 directory() 方法设置,进程环境将由 environment() 设置。

在使用 command() 方法设置执行命令参数后,然后由 start() 方法创建一个新的进程进而在系统中执行了我们设置的命令。

这么看来 java.lang.ProcessBuilder#start() 和 Runtime.exec(String[] cmdarray, String[] envp, File dir) 有些相似。

1
2
//简易示例代码
Process cmd = new ProcessBuilder(command).start();

代码展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class ExecProcessBuilder {
public static void main(String[] args) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder();
//ProcessBuilder processBuilder = new ProcessBuilder(("whoami"));
// 在Windows上运行这个命令,cmd, /c 参数是在运行后终止
processBuilder.command("cmd.exe", "/c", "ping www.baidu.com");
// 在Linux上运行
//processBuilder.command("bash", "-c", "ping baidu.com");
Process process = processBuilder.start();
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("GBK")));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
}

补充:

ProcessBuilder在实例化的时候也可以直接执行系统命令,但是没有command方法灵活

1
ProcessBuilder processBuilder = new ProcessBuilder(("whoami"));

start方法实际调用的是 Process start 方法

三. java.lang.UNIXProcess/ProcessImpl 执行命令

首先对于 UNIXProcess 和 ProcessImpl 可以理解本就是一个东西,因为在 JDK9 的时候把UNIXProcess 合并到了 ProcessImpl 当中了。

UNIXProcess 和 ProcessImpl 最终都是调用 native 执行系统命令的类,这个类提供了一个叫 forkAndExec 的native方法,如方法名所述主要是通过 fork&exec 来执行本地系统命令。

UNIXProcess类是*nix系统在 java 程序中的体现,可以使用该类创建新进程,实现与 fork 类似的功能(对于Windows系统,使用的是java.lang.ProcessImpl类)

ProcessImpl 是更为底层的实现,Runtime和ProcessBuilder执行命令实际上也是调用了ProcessImpl这个类

对于 ProcessImpl 类,我们不能直接调用需要配合使用反射。因为 java.lang.ProcessImpl 代码都被private 封装起来了。并没有设置公共的 API 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Map;

public class ExecProcessImpl {
public static void main(String[] args) throws Exception {
String[] cmds = new String[]{"whoami"};
Class clazz = Class.forName("java.lang.ProcessImpl");
Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
method.setAccessible(true);
Process process = (Process) method.invoke(null, cmds, null, ".", null, true);
String line = null;
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("GBK")));
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
}

invoke()方法: 用于动态调用对象的方法

四. 命令执行总结:

执行命令的类有 Runtime 、ProcessBuilder 和 ProcessImpl,其中Runtime 的 exec方法, ProcessBuilder 的 command方法 和 start方法 ,但 ProcessImpl 这个类是没有办法直接使用的 需要进行反射,调用 ProcessImpl 下面的 start 方法去执行命令

五. 命令执行代码审计:


Java命令执行操作
http://example.com/2025/06/04/Java命令执行操作/
作者
XCDH
发布于
2025年6月4日
许可协议