请考虑以下代码:
String commandf = "ls /etc | grep release";
try {
// Execute the command and wait for it to complete
Process child = Runtime.getRuntime().exec(commandf);
child.waitFor();
// Print the first 16 bytes of its output
InputStream i = child.getInputStream();
byte[] b = new byte[16];
i.read(b, 0, b.length);
System.out.println(new String(b));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
该程序的输出是:
/etc:
adduser.co
当我从shell运行时,它当然按预期工作:
poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release
互联网告诉我,由于管道行为不是跨平台的事实,在Java工厂生产Java的杰出人才无法保证管道工作。
我该怎么做?
我不会使用Java构造而不是grep
和sed
进行所有解析,因为如果我想更改语言,我将被迫重新编写解析用这种语言编写代码,这完全不行。
如何在调用shell命令时让Java进行管道和重定向?
答案 0 :(得分:168)
编写脚本,然后执行脚本而不是单独的命令。
管道是shell的一部分,所以你也可以这样做:
String[] cmd = {
"/bin/sh",
"-c",
"ls /etc | grep release"
};
Process p = Runtime.getRuntime().exec(cmd);
答案 1 :(得分:24)
我在Linux中遇到了类似的问题,除了它是“ps -ef | grep someprocess” 至少使用“ls”,您可以使用与语言无关(尽管速度较慢)的Java替换。例如:
File f = new File("C:\\");
String[] files = f.listFiles(new File("/home/tihamer"));
for (String file : files) {
if (file.matches(.*some.*)) { System.out.println(file); }
}
使用“ps”,它有点困难,因为Java似乎没有它的API。
我听说Sigar可以帮助我们: https://support.hyperic.com/display/SIGAR/Home
然而,最简单的解决方案(如Kaj所指出的)是将piped命令作为字符串数组执行。这是完整的代码:
try {
String line;
String[] cmd = { "/bin/sh", "-c", "ps -ef | grep export" };
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader in =
new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
} catch (Exception ex) {
ex.printStackTrace();
}
至于为什么String数组使用管道,而单个字符串不能......它是宇宙的奥秘之一(特别是如果你还没有读过源代码)。我怀疑这是因为当exec被赋予一个字符串时,它首先解析它(以我们不喜欢的方式)。相反,当给exec一个字符串数组时,它只是将它传递给操作系统而不解析它。
实际上,如果我们在忙碌的一天中抽出时间看看源代码 (在http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Runtime.java#Runtime.exec%28java.lang.String%2Cjava.lang.String[]%2Cjava.io.File%29),我们发现这正是发生的事情:
public Process [More ...] exec(String command, String[] envp, File dir)
throws IOException {
if (command.length() == 0)
throw new IllegalArgumentException("Empty command");
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
}
答案 2 :(得分:6)
创建运行时以运行每个进程。从第一个运行时获取OutputStream,并将其从第二个运行时复制到InputStream中。
答案 3 :(得分:1)
@Kaj接受的答案适用于Linux。这对于Windows是等效的:
String[] cmd = {
"cmd",
"/C",
"dir /B | findstr /R /C:"release""
};
Process p = Runtime.getRuntime().exec(cmd);