【问题标题】:java shell for executing/coordinating processes?用于执行/协调进程的java shell?
【发布时间】:2023-03-04 05:31:01
【问题描述】:

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

是否有一些 Java 类(标准或开源)实现了 shell,即您将命令字符串或脚本传递到其中的程序,它执行命令并相应地重定向标准 I/O/err,以便你可以传入foo | bar > baz.out 之类的字符串,它会运行foobar 程序,而无需在Java 之外运行另一个可执行文件?

(我所说的 shell 并不是指 BeanShell 或独立的 Rhino Javascript 解释器,它们是用于执行 Java 和 Javascript 代码的 Java 实现。我说的是用于执行非 Java 可执行文件并处理重定向管道的 Java 实现输入/输出。)

【问题讨论】:

  • 如果有这样的事情我会感到惊讶,因为 Java 对系统编程来说是一个如此痛苦的环境(例如文件操作的神秘错误条件等)。

标签: java shell


【解决方案1】:

好的,我已经解决了:

基本上,您需要使用 "-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();
}

显然,您应该对错误字符串做一些事情,但这是一个工作示例。

【讨论】:

  • 很有趣...在我的情况下,我不需要任何输出来将“常规外壳”输出到我的 Java 应用程序中,但它似乎对某些人有用。跨度>
  • 是的,我可以看到这样做的唯一缺点是如果您想将 java 中的内容通过管道传输到 shell 中会发生什么,因为您使用输出流将命令行传递给bash,您也不能使用它将内容通过管道传输到第一个命令中。如果你可以使用 bash -c 会更好,但我不知道如何使它工作。
【解决方案2】:

从 JDK 1.5 开始,java.lang.ProcessBuilder 也可以处理 std 和 err 流。它是 java.lang.Runtime 的替代品

【讨论】:

    【解决方案3】:

    您始终能够使用 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);
        }
    

    但是,如果您想在其中放置 shell 字符(例如管道和重定向),则必须编写自己的命令行解析器来链接流。据我所知,还没有写过。话虽如此,您是否可以仅使用 -c "ls | sort" 从 Java 调用 bash,然后读取输入。嗯,是时候做一些测试了。

    【讨论】:

      【解决方案4】:

      可以使用java提供的ProcessBuilder API。

      Runtime.getRuntime().exec(...) 采用字符串数组或单个字符串。 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;
              }
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2010-10-14
        • 2016-07-04
        • 1970-01-01
        • 2014-03-16
        • 2014-11-12
        • 2013-09-10
        • 2017-07-02
        • 2015-07-28
        • 2018-07-30
        相关资源
        最近更新 更多