我知道使用Runtime.exec,你传递一个本地程序来运行+参数。如果它是常规程序,您可以直接运行它。如果是shell脚本,则必须运行外部shell程序,如sh
或csh
或cmd.exe
。
是否存在一些实现shell的Java类(标准源或开源),这意味着您将命令字符串或脚本传递到的程序,执行命令并相应地重定向标准I / O / err,以便你可以传递像foo | bar > baz.out
这样的字符串,它会运行foo
和bar
程序而不必在Java之外运行另一个可执行文件吗?
(通过shell我不是指BeanShell或独立的Rhino Javascript解释器,它们是执行Java和Javascript代码的Java实现。我在谈论Java实现来执行非Java可执行文件并处理重定向的管道I / O。)
答案 0 :(得分:3)
好的,我已经解决了这个问题:
基本上,您需要使用"-s"
调用bash,然后将完整的命令字符串写入其中。
public class ShellExecutor {
private String stdinFlag;
private String shell;
public ShellExecutor(String shell, String stdinFlag)
{
this.shell = shell;
this.stdinFlag = stdinFlag;
}
public String execute(String cmdLine) throws IOException
{
StringBuilder sb = new StringBuilder();
Runtime run = Runtime.getRuntime();
System.out.println(shell);
Process pr = run.exec(cmdLine);
BufferedWriter bufWr = new BufferedWriter(
new OutputStreamWriter(pr.getOutputStream()));
bufWr.write(cmdLine);
try
{
pr.waitFor();
} catch (InterruptedException e) {}
BufferedReader buf = new BufferedReader(
new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line = buf.readLine()) != null)
{
sb.append(line + "\n");
}
return sb.toString();
}
}
然后像这样使用它:
ShellExecutor excutor = new ShellExecutor("/bin/bash", "-s");
try {
System.out.println(excutor.execute("ls / | sort -r"));
} catch (IOException e) {
e.printStackTrace();
}
显然,你应该对错误字符串做些什么,但这是一个有效的例子。
答案 1 :(得分:2)
从JDK 1.5开始,java.lang.ProcessBuilder也处理std和err流。它有点替代java.lang.Runtime
答案 2 :(得分:2)
您始终可以使用Runtime.exec
处理流e.g。
String cmd = "ls -al";
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
pr.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null) {
System.out.println(line);
}
但是,如果要在其中放置管道和重定向等shell字符,则必须编写自己的命令行解析器来链接流。据我所知,还没有人写过。话虽这么说,你可以用例如-c“ls | sort”从Java调用bash,然后读取输入。是时候做一些测试了。
答案 3 :(得分:1)
您可以使用java提供的ProcessBuilder API。
Runtime.getRuntime().exec(...)
取一个字符串数组或一个字符串。在将字符串数组传递到带有字符串数组的exec()
重载之一之前,exec()
的单字符串重载会将字符串标记为参数数组。另一方面,ProcessBuilder
构造函数只接受字符串的varargs数组或字符串List,其中数组或列表中的每个字符串都被假定为单独的参数。无论哪种方式,获得的参数然后连接成一个字符串,传递给OS执行。
在以下链接中查找更多详细信息 Difference between ProcessBuilder and Runtime.exec()
执行命令的示例程序。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.List;
public class ProcessBuilderTest {
static ProcessBuilder processBuilder = null;
static Process spawnProcess = null;
static int exitValue;
static int pid;
static List<String> commands;
public static void main(String[] args) {
runSqoop();
}
public static void runSqoop() {
String[] commands = { "ssh", "node", "commands" };
processBuilder = new ProcessBuilder(commands);
try {
System.out.println("Executing " + commands.toString());
spawnProcess = processBuilder.inheritIO().start();
try {
exitValue = spawnProcess.waitFor();
pid = getPID(spawnProcess);
System.out.println("The PID is " + pid);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("Process exited with the status :" + exitValue);
} catch (Exception e) {
e.printStackTrace();
}
}
public static int getPID(Process process) {
try {
Class<?> processImplClass = process.getClass();
Field fpid = processImplClass.getDeclaredField("pid");
if (!fpid.isAccessible()) {
fpid.setAccessible(true);
}
return fpid.getInt(process);
} catch (Exception e) {
System.out.println(e.getMessage());
return -1;
}
}
}