文
章
目
录
章
目
录
Java开发的项目,部署到Linux系统后,偶尔会使用Java调用Shell命令和脚本,比如修改了某些参数配置需要重启tomcat服务器或者重启系统等等,虽然使用频率不高,但是我们还是有必要了解下如何使用Java执行Shell命令和Shell脚本。JDK给我们提拱了两种实现方案,一种是Runtime.getRuntime().exec() API方法,另一种是通过ProcessBuilder来实现该功能,其中ProcessBuilder更灵活也更可取。
一、Runtime方法:
1、介绍
我们先了解下其具体的方法有哪些:
// 在单独的进程中执行指定的字符串命令 Process exec(String command) // 在单独的进程中执行指定命令和变量 Process exec(String[] cmdarray) // 在指定环境的独立进程中执行指定命令和变量 Process exec(String[] cmdarray, String[] envp) // 在指定环境和工作目录的独立进程中执行指定的命令和变量 Process exec(String[] cmdarray, String[] envp, File dir) // 在指定环境的单独进程中执行指定的字符串命令 Process exec(String command, String[] envp) // 在有指定环境和工作目录的独立进程中执行指定的字符串命令 Process exec(String command, String[] envp, File dir)
说明下参数含义:
1)command: 一条指定的系统命令,比如 : echo hello。
2)cmdarray: 包含所调用命令及其参数的数组。
3)envp: 字符串数组,其中每个元素的环境变量的设置格式为name=value;如果子进程应该继承当前进程的环境,则该参数为 null。
4)dir: 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为 null。
5)Process:调用exec方法后JVM会启动一个Precess进程返回, 我们可以调用如下方法:
// 检测执行是否正确。该方法使当前线程等待,返回0 表示正常终止;否则,就表示异常失败 abstract int waitFor() // 获取返回值。通过输入流获取脚本会指令输出的值。 abstract InputStream getInputStream()
2、执行shell命令
public void callCmd(String command){
try {
Process process = Runtime.getRuntime().exec(command);
int status = process.waitFor();
if(status == 0){
System.out.println("执行成功");
}else {
System.out.println("执行失败");
}
}catch (Exception e){
e.printStackTrace();
}
}
3、执行shell脚本
// path为shell脚本绝对路径
public String callScript(String path) {
String result = null;
BufferedReader br = null;
try {
Process ps = Runtime.getRuntime().exec(path);
ps.waitFor();
br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
result = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
其他的api方法就不再演示了,可以自行研究下。
二、ProcessBuilder方法:
ProcessBuilder相比Runtime方法更可取,因为能够定制一些细节。例如:
- 使用builder.directory()方法,改变正在运行Shell命令的工作目录
- 使用builder.environment()方法,设置自定义键值对作为环境变量
- 重定向输入和输出流值自定义流
- 使用build.inheritio()方法将它们都继承到当前JVM进程的流中
ProcessBuilder执行主要分成三步:
- 构建ProcessBuilder
- 构建外部命令
- 执行start
案例代码:
1、执行普通指令
// 使用touch在/usr/test下新建my.txt文件
public void test() throws IOException, InterruptedException {
// 构建一个命令
List<String> command = new ArrayList<>();
// 该命令的位置,可以用 which touch 查找
command.add("/usr/bin/touch");
command.add("my.txt");
// 构建一个 processBuilder
ProcessBuilder processBuilder = new ProcessBuilder();
// 切换工作目录,也可以不写这个,直接在command 里面 加上
processBuilder.directory(new File("/usr/test"));
// command.add("/usr/test")
// 添加命令
processBuilder.command(command);
// 执行
Process start = processBuilder.start();
if (start.isAlive()) {
start.waitFor();
}
}
2、执行有输出内容的指令
public void test2() throws IOException, InterruptedException {
// 构建一个命令
List<String> command = new ArrayList<>();
// 该命令的位置,可以用 which 查找
command.add("/bin/ls");
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(new File("/usr/test"));
// 设置为 true 后,错误会和标准输出一样输出
processBuilder.redirectErrorStream(true);
processBuilder.command(command);
Process process = processBuilder.start();
InputStream is = process.getInputStream();
// 使用 hutool 工具类 解析 inputStream
FastByteArrayOutputStream read = IoUtil.read(is);
System.out.println(read);
is.close();
if(process.isAlive()){
process.waitFor();
}
}
三、总结
以上就是关于如何使用Java执行Shell命令和Shell脚本的内容,有些具体的操作还需要自己在实践中摸索,不断学习,才能更好地运用自如。





