如何使pipe道与Runtime.exec()?
考虑下面的代码:
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
互联网告诉我,由于pipe道行为不是跨平台的事实,在生产Java的Java工厂工作的聪明人不能保证pipe道工作。
我该怎么做?
我不会使用Java构造而不是grep
和sed
来进行所有的parsing,因为如果我想改变语言,我将被迫重新编写我的parsing代码,这是完全没有用的,走。
如何让Java在调用shell命令时进行pipe道和redirect?
写一个脚本,并执行脚本而不是单独的命令。
pipe道是壳的一部分,所以你也可以这样做:
String[] cmd = { "/bin/sh", "-c", "ls /etc | grep release" }; Process p = Runtime.getRuntime().exec(cmd);
我在Linux中遇到了类似的问题,除了是“ps -ef | grep someprocess”。
至less在“ls”你有一个语言无关的(尽pipe比较慢)的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
然而,最简单的解决scheme(正如Kaj指出的那样)是将pipe道命令作为string数组来执行。 以下是完整的代码:
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数组与pipe道工作,而单个string不…这是宇宙的奥秘之一(特别是如果你还没有阅读源代码)。 我怀疑这是因为当exec被赋予一个string时,它首先parsing它(以我们不喜欢的方式)。 相比之下,当exec被赋予一个string数组时,它只是将它传递给操作系统而不parsing它。
实际上,如果我们抽出一天时间来看看源代码( 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); }
创build一个运行时来运行每个进程。 从第一个运行时获取OutputStream并将其复制到第二个的InputStream中。