1. 概述
在日常开发过程中,我们经常会需要调用系统的命令行,比如执行一些系统工具/库来压缩(变换)图片等。本文将介绍从Java代码中执行shell命令的两种方法。
第一种是使用Runtime类并调用其exec方法。
第二种更可定制的方法是创建和使用ProcessBuilder实例。
2. 操作系统依赖性
在我们要创建执行shell命令的新Process之前,我们需要首先确定运行JVM的操作系统。
这是因为,在Windows上,我们需要将命令作为参数运行到cmd.exe shell,在所有其他操作系统上我们可以发出一个名为sh的标准shell :
1 | boolean isWindows = System.getProperty("os.name") |
3. 输入和输出
此外, 我们需要一种方法来 Hook 住输入和输出流。
至少必须消费掉输出 - 否则我们的进程不会成功返回,而是会挂起。
让我们实现一个名为StreamGobbler的常用类,它使用一个InputStream:
1 | private static class StreamGobbler implements Runnable { |
注意:此类实现了Runnable接口,这意味着它可以由任何Executor执行。
4. Runtime.exec()
对Runtime.exec()的方法调用是一种简单的,尚未定制的生成新子进程的方法。
在下面的示例中,我们将请求用户主目录的目录列表并将其打印到控制台:
1 | String homeDirectory = System.getProperty("user.home"); |
5. ProcessBuilder
对于计算问题的第二个实现,我们将使用ProcessBuilder。这比Runtime方法更受欢迎,因为我们可以自定义一些细节。
例如,我们能够:
- 使用builder.directory()更改我们的shell命令正在运行的工作目录
- 使用builder.environment()将自定义键值映射设置为环境
- 将自定义输入和输出流重定向
- 使用builder.inheritIO()将它们都继承到当前JVM进程的流
1 | ProcessBuilder builder = new ProcessBuilder(); |
六,结论
正如我们在本快速教程中看到的,我们可以用两种不同的方式在Java中执行shell命令。
通常,如果您计划自定义生成进程的执行,例如更改其工作目录,则应考虑使用ProcessBuilder。