Java Execute Shell Script 捆绑在 JAR 中

2022-09-02 04:37:16

可能的重复:
在 jar 文件中执行 shell 脚本。如何提取?

我有一个shell脚本打包到“引擎”包中的JAR文件中。

在我的程序中,我正在使用Process和ProcessBuilder运行shell命令。这一切都很好。

如果我在计算机上指定shell脚本的路径,那么程序工作正常。但是,如果我将shell脚本打包到我的JAR中并像这样访问它:

scriptLocation = this.getClass().getResource("/engine/shell-script.sh").toString();

并运行该程序,然后我得到以下错误:

java.io.IOException: Cannot run program "file:/Users/USERNAME/Desktop/Application-Name.jar!/engine/shell-script.sh": error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:460)
    at java.lang.Runtime.exec(Runtime.java:593)
    at java.lang.Runtime.exec(Runtime.java:431)
    at java.lang.Runtime.exec(Runtime.java:328)
    at engine.Download$1.run(Download.java:39)
    at java.lang.Thread.run(Thread.java:680)
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:53)
    at java.lang.ProcessImpl.start(ProcessImpl.java:91)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:453)
    ... 5 more

我开始认为这不能完成,我非常想提供这个shell脚本作为应用程序的一部分,可以做到吗?

提前感谢大家。

======== 更新 ===========

我最终解决了这个问题。Shell 不能在 JAR 捆绑包中执行脚本,它不是关于 Java,而是 shell。我通过执行以下操作来解决此问题:

Java 有一个 createTempFile() 方法(可以选择在应用程序终止后删除该文件),调用它,并将要访问的 JAR 捆绑包中的文件写入此临时文件。然后,您可以在本地文件系统上拥有 shell 脚本,并能够执行该脚本。


答案 1

它不是关于Java,而是关于shell。据我所知,shell 解释器无法执行驻留在 zip 文件中的脚本。所以你在这里有几个选择:

  1. 从 Java 程序中以文本文件的形式读取 shell 脚本。创建一个临时文件(在临时目录或任何其他相关位置,并将文件的内容复制到那里。然后用这个时态脚本调用 shell 解释器。我相信这是最好的方法

  2. 由于 jar 是一个 zip,因此您可以从 shell 中解压缩它,找到一个脚本并执行 shell。同样,这更加尴尬,而且相当错误,但从技术上讲,它应该有效。

  3. 如果你的脚本中没有低级的东西,你可以考虑将逻辑重写为时髦的脚本(也许你会发现有用的groosh项目)。然后从内存中调用时髦代码,而不是从文件中调用。

好吧,我没有想法,如果我是你,我会实施第一个解决方案:)祝你好运,希望这有帮助


答案 2

最简单的解决方案是让应用程序将 shell 脚本提取到一个临时位置,然后从那里执行它。

您可以通过调用 File.createTempFile(String, String) 在 Java 中生成一个临时文件。

你可以做的另一件事是传递脚本的内容,从你的jar加载,作为shell的标准输入。

作为简化,如果我有一个包含脚本的存档,这将执行它:a.zipa.sh

$ unzip -p a.zip a.sh | bash

从 Java 程序中,您可以执行以下操作:

import java.io.*;
class Test{

  public static void main(String[]args) throws Exception {

    StringBuilder sb = new StringBuilder();

    // You're not strictly speaking executing a shell script but
    // rather programatically typing commands into the shell
    // sb.append("#!/bin/bash\n");
    sb.append("echo Hello world!\n");
    sb.append("cd /tmp\n");
    sb.append("echo current directory: `pwd`\n");

    // Start the shell
    ProcessBuilder pb = new ProcessBuilder("/bin/bash");
    Process bash = pb.start();

    // Pass commands to the shell
    PrintStream ps = new PrintStream(bash.getOutputStream());
    ps.println(sb);
    ps.close();

    // Get an InputStream for the stdout of the shell
    BufferedReader br = new BufferedReader(
        new InputStreamReader(bash.getInputStream()));

    // Retrieve and print output
    String line;
    while (null != (line = br.readLine())) {
      System.out.println("> "+line);
    }
    br.close();

    // Make sure the shell has terminated, print out exit value
    System.out.println("Exit code: " + bash.waitFor());

  }

}

推荐