JAR 中捆绑的 Java 执行 Shell 脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12875115/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 10:35:49  来源:igfitidea点击:

Java Execute Shell Script Bundled within JAR

javashell

提问by Cristian

Possible Duplicate:
Executing a shell script inside a jar file. How to extract?

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

I have a shell script packaged into my JAR file within the 'engine' package.

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

In my program I am running a shell command using Process and ProcessBuilder. This all works fine.

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

If I specify the path to the shell script on my computer then the program works fine. If however I package the shell script into my JAR and access it like this:

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

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

And run the program, then I get the following error:

并运行该程序,然后出现以下错误:

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.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

I'm starting to think this cannot be done, I would very much like to provide this shell-script as part of the application, can it be done?

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

Thanks in advance everyone.

提前谢谢大家。

======== UPDATE ==========

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

I eventually solved this problem. Shell cannot execute scripts within a JAR bundle, it's not about Java, but shell. I fixed this by doing the following:

我最终解决了这个问题。Shell 无法在 JAR 包中执行脚本,这与 Java 无关,而是与 shell 相关。我通过执行以下操作解决了这个问题:

Java has a createTempFile() method (with option to delete the file once the application has been terminated), invoke this, and write the file within the JAR bundle that you want to access to this temp file. You then have the shell script on the local filesystem, and are able to execute the script.

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

采纳答案by Mark Bramnik

Its not about Java, its about shell. As far as I know shell interpreter can't execute scripts that reside in the zip file. So you have a couple of options here:

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

  1. Read the shell script as a text file from within your java program. create a temporal file (in temp dir or any other relevant place and copy the content of the file there. And then call the shell interpreter with this temporal script. I believe its the best approach

  2. Since jar is a zip, you can unzip it from within the shell find a script and execute the shell. Again this is more awkward and rather wrong, but technically it should work.

  3. If you don't have low level stuff in your script, you can consider to rewrite the logic to groovy script (maybe you'll find useful groosh project). Then call the groovy code from the memory and not from the file.

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

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

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

Well, I'm out of ideas, If I were you, I would implement the first solution :) Good luck and hope this helps

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

回答by Vlad

The simplest solution would be to have your application extract the shell script into a temporary location and execute it from there.

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

You can produce a temporary file in Java by calling File.createTempFile(String, String).

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

Another thing that you could possibly do is pass the contents of the script, as loaded from your jar, as the standard input of the shell.

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

As a simplification, if I had an archive a.zipcontaining a script a.sh, this would execute it:

为简化起见,如果我有一个a.zip包含 script的存档a.sh,这将执行它:

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

From a Java program, you could do the following:

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

  }

}

回答by rich

I usually just do...

我通常只是做...

$ jar xf myapp.jar run.sh && ./run.sh && rm run.sh

...which you could call from a Runtime.exec() if necessary.

...如有必要,您可以从 Runtime.exec() 调用它。