2009-10-20 25 views
3

我知道关于使用Runtime.exec,你传递一个本地程序来运行+参数。如果是普通程序,可以直接运行。如果是外壳脚本,则必须运行外部外壳程序,如shcshcmd.exe用于执行/协调进程的java shell?

是否有一些Java类(标准或开放源代码)实现了一个shell,这意味着您将一个命令字符串或脚本传入的程序,相应地执行命令并重定向标准I/O/err你可以传入像foo | bar > baz.out这样的字符串,并且它将运行foobar程序,而不必在Java之外运行另一个可执行文件?我并不是说BeanShell或独立的Rhino Javascript解释器,这些是执行Java和Javascript代码的Java实现。我正在谈论Java实现来执行非Java可执行文件,并处理重定向I/O。)

+0

,如果有这样的事情,因为Java是系统编程这样一个痛苦的环境下(如在文件操作谜错误条件等),我会感到惊讶。 – 2009-10-20 18:40:14

回答

2

由于JDK 1.5中有java.lang.ProcessBuilder,它也可以处理std和err流。这有点更换为java.lang.Runtime中

2

你总是能够用的Runtime.exec

例如处理流

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); 
    } 

但是,如果你想要把诸如管壳字符和重定向在那里你必须写你自己的命令行分析器哪个环节出流。据我所知,还没有人写过。话虽如此,你能否仅仅用-c“ls | sort”从Java调用bash,然后读取输入。嗯时间做一些测试。

3

好吧,我的工作了:

基本上,你需要调用的bash与"-s",然后完整的命令字符串写入。

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(); 
} 

显然,你有啥可做一些与错误字符串但是这是一个工作的例子。

+0

有趣...在我的情况下,我不需要任何输出来将“常规shell”导出到我的Java应用程序中,但它似乎对某些人可能有用。 – 2009-10-20 20:16:02

+0

是的,我可以看到这样做的唯一缺点是如果你想从java中将东西流入shell,会发生什么情况,因为你正在使用outputstream将命令行传递给bash,所以你也不能用它来将东西传送到第一个命令中。如果你可以使用bash -c会更好,但我无法弄清楚如何完成这项工作。 – Benj 2009-10-20 20:29:06

1

您可以使用java提供的ProcessBuilder API。

Runtime.getRuntime().exec(...)可以是一个字符串数组或一个字符串。在将字符串数组传递到接受字符串数组的其中一个接口上之前,exec()的单字符串重载将字符串标记为参数数组。另一方面,ProcessBuilder构造函数只采用可变长字符串数组或字符串列表,其中数组或列表中的每个字符串被假定为单个参数。无论采用哪种方式,所获得的参数都会被加入到一个传递给操作系统来执行的字符串中。

在以下链接了解更多详细 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; 
     } 
    } 

}