在Java中执行Shell脚本
在Java中执行Shell脚本有几种常见方法,下面我将介绍几种主要的方式:

使用Runtime.exec()
这是最直接的方法,但需要注意处理输入流和错误流:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ShellExecutor {
public static void main(String[] args) {
try {
// 执行shell命令
Process process = Runtime.getRuntime().exec("ls -l");
// 读取命令输出
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 等待命令执行完成
int exitCode = process.waitFor();
System.out.println("Exit code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用ProcessBuilder(推荐)
ProcessBuilder提供了更好的控制能力:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
public class ShellExecutor {
public static void main(String[] args) {
try {
// 创建ProcessBuilder
ProcessBuilder pb = new ProcessBuilder("ls", "-l");
// 设置工作目录(可选)
pb.directory(new File("/path/to/directory"));
// 启动进程
Process process = pb.start();
// 读取输出
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 等待命令完成
int exitCode = process.waitFor();
System.out.println("Exit code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行复杂的Shell脚本
如果需要执行复杂的Shell脚本,可以将其保存为文件然后执行:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
public class ShellScriptExecutor {
public static void main(String[] args) {
try {
// 假设脚本文件在当前目录下
File scriptFile = new File("script.sh");
ProcessBuilder pb = new ProcessBuilder("bash", scriptFile.getAbsolutePath());
pb.directory(scriptFile.getParentFile());
Process process = pb.start();
// 合并输出和错误流
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
BufferedReader errorReader = new BufferedReader(
new InputStreamReader(process.getErrorStream()));
// 读取标准输出
String line;
System.out.println("Output:");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 读取错误输出
System.out.println("\nErrors:");
while ((line = errorReader.readLine()) != null) {
System.out.println(line);
}
int exitCode = process.waitFor();
System.out.println("\nExit code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用第三方库
也可以使用第三方库如Apache Commons Exec来简化操作:

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
import java.io.ByteArrayOutputStream;
public class CommonsExecExample {
public static void main(String[] args) {
try {
CommandLine cmdLine = CommandLine.parse("ls -l");
DefaultExecutor executor = new DefaultExecutor();
// 创建输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
executor.setStreamHandler(streamHandler);
// 执行命令
int exitCode = executor.execute(cmdLine);
System.out.println("Exit code: " + exitCode);
System.out.println("Output:\n" + outputStream.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意事项
- 线程安全:确保正确处理输入流和错误流,否则可能导致进程阻塞
- 路径问题:使用绝对路径或正确设置工作目录
- 权限问题:确保Java进程有执行脚本的权限
- 跨平台:注意不同操作系统的命令差异
- 超时处理:长时间运行的脚本应设置超时
- 环境变量:如需特殊环境变量,应在ProcessBuilder中设置
处理超时的示例
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class TimeoutExample {
public static void main(String[] args) {
try {
Process process = Runtime.getRuntime().exec("sleep 10");
// 设置超时5秒
Thread.sleep(5000);
// 检查进程是否还在运行
if (process.isAlive()) {
process.destroyForcibly();
System.out.println("Process timed out and was killed");
}
int exitCode = process.waitFor();
System.out.println("Exit code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}
选择哪种方法取决于你的具体需求,对于简单的命令,Runtime.exec()或ProcessBuilder就足够了;对于更复杂的场景,可以考虑使用第三方库。

