用于执行/协调进程的java shell?

时间:2009-10-20 18:13:59

标签: java shell

我知道使用Runtime.exec,你传递一个本地程序来运行+参数。如果它是常规程序,您可以直接运行它。如果是shell脚本,则必须运行外部shell程序,如shcshcmd.exe

是否存在一些实现shell的Java类(标准源或开源),这意味着您将命令字符串或脚本传递到的程序,执行命令并相应地重定向标准I / O / err,以便你可以传递像foo | bar > baz.out这样的字符串,它会运行foobar程序而不必在Java之外运行另一个可执行文件吗?

(通过shell我不是指BeanShell或独立的Rhino Javascript解释器,它们是执行Java和Javascript代码的Java实现。我在谈论Java实现来执行非Java可执行文件并处理重定向的管道I / O。)

4 个答案:

答案 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;
        }
    }

}