2012-10-13 152 views
8

Possible Duplicate:
Executing a shell script inside a jar file. How to extract?资源下载JAR

内执行shell脚本捆绑我有“引擎”包内打包到我的JAR文件中的shell脚本。

在我的程序中,我使用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脚本作为应用程序的一部分,它可以做到吗?

在此先感谢大家。

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

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

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

回答

4

其不是关于Java,而是关于shell。据我所知,shell解释器不能执行驻留在zip文件中的脚本。因此,您在这里有几个选项:

  1. 从您的Java程序中读取shell脚本作为文本文件。 创建中的临时文件(在临时目录或任何其他相关地方和复制文件存在的内容。然后调用这个时间脚本命令解释程序。 我相信它的最好的办法

  2. 由于罐子是zip,您可以从shell中解压缩,找到一个脚本并执行该shell。再次,这是更尴尬,而且错误,但技术上它应该工作。

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

嗯,我的想法,如果我是你,我将实现第一个解决方案:) 祝你好运,希望这有助于

+0

感谢您的回答,我会看到我如何从jar文件中提取shell脚本到临时位置,然后从那里提取它,你知道我怎么能做到这一点或知道任何链接?感谢您的回答! – Cristian

+0

正如我在别处提到的,你可以这样做:unzip -p JARFILE SCRIPTFILE |庆典。这基本上会从jar中提取文件,但实际上并不创建文件。 – Jay

3

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

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

您可能做的另一件事是从脚本中加载脚本的内容,作为shell的标准输入。

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

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

    } 

} 
+0

我不想将文件复制到用户的系统上,我该如何去传递脚本的内容以便在程序中使用? – Cristian

+0

在我看来非常有趣的解决方案,感谢分享 –

0

我通常只是做...

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

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

+0

如果这个jar文件是从命令行运行的,但它是一个可运行的jar文件 – Cristian

+0

通过Runtime.exec()执行它应该能够解决这个问题,尽管它确实很难看。 – rich