Как сделать труб работы со средой выполнения.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
когда я бегу от оболочки, конечно, он работает так, как ожидалось:
poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release
интернет говорит мне, что из-за того, что поведение трубы не является кросс-платформенным, блестящие умы, которые работают на фабрике Java, производящей Java, не могут гарантировать, что трубы работают.
как я могу это сделать?
Я не собираюсь делать весь мой разбор с помощью Java конструкции, а не grep
и sed
, потому что если я хочу изменить язык, я буду вынужден переписать парсинг кода на этом языке, который совершенно не подходит.
как я могу заставить Java выполнять конвейер и перенаправление при вызове команд оболочки?
3 ответа:
написать сценарий и выполнить сценарий вместо отдельных команд.
Труба является частью оболочки, так что вы также можете сделать что-то вроде этого:
String[] cmd = { "/bin/sh", "-c", "ls /etc | grep release" }; Process p = Runtime.getRuntime().exec(cmd);
я столкнулся с аналогичной проблемой в 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 для этого.
Я слышал, что сигар может помочь нам: https://support.hyperic.com/display/SIGAR/Home
самое простое решение, однако, (как указал Кай) выполнить команду 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(); }
что касается того, почему массив строк работает с трубой, а одна строка-нет... это одна из тайн Вселенной (особенно если вы не читали исходный код). Я подозреваю, что это потому, что когда exec дается одна строка, он сначала анализирует ее (таким образом, что нам не нравится). Напротив, когда exec получает массив строк, он просто передает его в операционную систему без разбора оно.
на самом деле, если мы возьмем время из напряженного дня и посмотрим на исходный код (at 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); }