Java主要通过Runtime和Process执行Linux命令,Process是Runtime.exec的返回值,可以用来对执行过程进行后续操作(获取结果、发送命令、等待结果)
1.如果Linux命令需要执行很长时间,需要调用Process的waitFor方法,等待后台任务执行完毕,否则其会自动退出
2.waitFor方法可以设置超时时间,防止一直等待
3.执行需要特定环境变量的命令时,可以使用ProcessBuilder的getEnvironment
4.执行多个命令组合时需要使用{“/bin/sh”, cmd}
package com.sisyphus.util;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/*
* Java主要通过Runtime和Process执行Linux命令,Process是Runtime.exec的返回值,可以用来对执行过程进行后续操作(获取结果、发送命令、等待结果)
* 1.如果Linux命令需要执行很长时间,需要调用Process的waitFor方法,等待后台任务执行完毕,否则其会自动退出
* 2.waitFor方法可以设置超时时间,防止一直等待
* 3.执行需要特定环境变量的命令时,可以使用ProcessBuilder的getEnvironment
* 4.执行多个命令组合时需要使用{"/bin/sh", cmd}
* */
public class LinuxCommandUtils {
/*
* 2022-9-2
* 【服务器执行Linux命令方法】
* commands:需要执行的命令行
* 【return】:命令的执行后,系统返回的信息
* 【方法调用样例】:
* List commands = new ArrayList<>();
* commands.add("cd /home/app");
* commands.add("touch test.txt");
* LinuxCommandUtils.executeCommands(commands);
* */
public static List<String> executeCommands(List<String> commands){
List<String> rspList = new ArrayList<>();
Runtime run = Runtime.getRuntime();
try {
Process proc = run.exec("/bin/bash", null, null);
if(proc != null){
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
for(String line : commands){
System.out.println("执行命令行:" + line);
out.println(line);
}
out.println("exit"); //这个命令必须执行,否则in流不结束
System.out.println("exit成功执行");
String rspLine = "";
while((rspLine = in.readLine()) != null){
System.out.println("系统返回结果:" + rspLine);
rspList.add(rspLine);
}
System.out.println("proc等待中...");
proc.waitFor();
System.out.println("proc等待结束...");
in.close();;
out.close();
proc.destroy();
}else{
System.out.println("proc为空");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return rspList;
}
}
每个Java应用程序都有一个Runtime类的Runtime ,允许应用程序与运行应用程序的环境进行接口,比如返回Java虚拟机中的可用内存量、返回Java虚拟机中的内存总量,以及运行垃圾回收器等等
应用程序无法创建自己的此类的实例,当前运行时可以从getRuntime方法获得
ProcessBuilder.start()和Runtime.exec方法创建一个本机进程并返回一个Process子类的Process ,可以用来控制进程并获取有关它的信息。 Process类提供了用于执行进程输入,执行到进程的输出,等待进程完成,检查进程的退出状态以及破坏(杀死)进程的方法
创建进程的方法可能不适用于某些本机平台上的特殊进程,例如本机窗口进程,守护进程,Microsoft Windows上的Win16 / DOS进程或shell脚本
默认情况下,创建的子进程没有自己的终端或控制台。 其所有的标准I / O(即标准输入,标准输出,标准错误)操作将被重定向到父进程,在那里他们可以经由使用所述方法获得的流进行访问getOutputStream() , getInputStream()和getErrorStream() 。 父进程使用这些流将输入提供给子进程并从子进程获取输出。 因为一些本地平台只为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁
将对象的格式表示打印到文本输出流。 这个类实现了全部在发现print种方法PrintStream 。 它不包含用于编写原始字节的方法,程序应使用未编码的字节流
不像PrintStream类,如果启用自动刷新,它只会在调用的println,printf,或format方法来完成,而不是当一个换行符恰好是输出。 这些方法使用平台自己的行分隔符而不是换行符
这个类中的方法不会抛出I/O异常,尽管它的一些构造函数可能。 客户可以通过调用checkError()查询是否发生错误
构造方法
可见我们使用的构造方法是PrintWriter(OutputStream out, boolean autoFlush),那么这个autoFlush是什么意思呢?
简单来说,如果不开启autoFlush,那么只有当缓冲区满了,才会将内容输出,如果一直没有内容输入到缓冲区,或者内容无法装满缓冲区,线程就会一直阻塞在这里
题外话
与BufferedWriter的对比:
更细节方面的不同: