21

重複の可能性:
jarファイル内でシェルスクリプトを実行します。抽出する方法は?

'engine'パッケージ内のJARファイルにシェルスクリプトがパッケージ化されています。

私のプログラムでは、ProcessとProcessBuilderを使用してシェルコマンドを実行しています。これはすべて正常に機能します。

コンピューターでシェルスクリプトへのパスを指定すると、プログラムは正常に機能します。ただし、シェルスクリプトを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はJARバンドル内でスクリプトを実行できません。これは、Javaではなく、シェルに関するものです。私は次のようにしてこれを修正しました:

JavaにはcreateTempFile()メソッド(アプリケーションが終了したらファイルを削除するオプション付き)があり、これを呼び出して、この一時ファイルにアクセスするJARバンドル内にファイルを書き込みます。これで、ローカルファイルシステムにシェルスクリプトが作成され、スクリプトを実行できるようになります。

4

3 に答える 3

11

それはJavaについてではなく、シェルについてです。私の知る限り、シェルインタープリターはzipファイルにあるスクリプトを実行できません。したがって、ここにはいくつかのオプションがあります。

  1. Javaプログラム内からシェルスクリプトをテキストファイルとして読み取ります。一時ファイルを作成します(一時ディレクトリまたはその他の関連する場所にファイルの内容をコピーします。次に、この一時スクリプトを使用してシェルインタープリターを呼び出します。これが最善のアプローチだと思います。

  2. jarはzipであるため、シェル内から解凍してスクリプトを見つけ、シェルを実行できます。繰り返しますが、これはもっと厄介でかなり間違っていますが、技術的には機能するはずです。

  3. スクリプトに低レベルのものが含まれていない場合は、ロジックをGroovyスクリプトに書き直すことを検討できます(おそらく、便利なgrooshプロジェクトが見つかるでしょう)。次に、ファイルからではなく、メモリからGroovyコードを呼び出します。

まあ、私はアイデアがありません、もし私があなたなら、私は最初の解決策を実装するでしょう:)頑張って、これが役立つことを願っています

于 2012-10-13T17:39:49.330 に答える
5

最も簡単な解決策は、アプリケーションにシェルスクリプトを一時的な場所に抽出させ、そこから実行させることです。

を呼び出すことにより、Javaで一時ファイルを作成できますFile.createTempFile(String, String)

おそらくできるもう1つのことは、jarからロードされたスクリプトの内容を、シェルの標準入力として渡すことです。

a.zip簡単にするために、スクリプトを含むアーカイブがある場合a.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());

  }

}
于 2012-10-13T17:29:32.860 に答える
0

私は通常ただします...

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

...必要に応じてRuntime.exec()から呼び出すことができます。

于 2012-10-13T18:43:07.687 に答える