2016-02-25 20 views
5

Để rõ ràng, bằng tập tin thực thi, tôi không có nghĩa là byte đã sẵn sàng cho bộ vi xử lý. Ví dụ: một tập lệnh bash, được diễn giải và không thực thi được, sẽ trở thành thực thi khi một shebang được thêm vào đầu chỉ định tập lệnh sẽ được chạy bởi /bin/bash hoặc /bin/sh hoặc bất kỳ chương trình nào sẽ diễn giải nó.Có thể thực hiện bất kỳ ngôn ngữ nào có thể thực thi được không?

Tôi đã tự hỏi liệu có thể thực hiện tương tự với các ngôn ngữ kịch bản khác không? Và nếu có, thật sự dễ dàng như việc thêm một shebang tham chiếu đến chương trình diễn giải (tức là #!/usr/bin/python đối với tập lệnh Python hoặc #!/usr/local/bin/node cho JavaScript)?

Tôi cũng tự hỏi có thể làm gì với Java, ngôn ngữ này không phải là ngôn ngữ kịch bản nhưng chắc chắn không thực thi được. Có vẻ như Java sẽ khó bởi vì người dùng không thực sự có cơ hội thêm một shebang vào tệp được biên dịch.

Trả lời

3

Bạn chắc chắn có thể tạo một tập tin:

#!/any/executable/program args 
...input goes here... 

Bạn có thể làm điều đó với Java

#!/path/bin/java mainclass 
...this is System.in... 
+0

Ahh như vậy với Java các tập tin .class sẽ phải được lưu trữ ở đâu và được tham chiếu bởi thực thi vẫn còn? –

+0

Có, đó là chính xác và bạn phải chắc chắn rằng classpath là chính xác trước khi chạy nó. Vì vậy, nó là thực tế hơn để sử dụng một kịch bản sh thường. –

+0

Thật thú vị. Tôi không biết bạn có thể vượt qua các đối số sau khi shebang quá.Tôi đoán đó là những gì tôi nhận được để được tự dạy haha. Đã phê duyệt câu trả lời! –

2

số Đó là không thể đưa một tiếng nổ cô trên bất kỳ kịch bản và nó sẽ thực thi. Bash dựa vào thực tế là tệp có shebang bỏ qua các dòng bắt đầu bằng #. Do đó bất kỳ ngôn ngữ kịch bản hoặc mã byte nào có thể bỏ qua dòng đầu tiên với shebang sẽ hoạt động.

Nếu ngôn ngữ của bạn không hỗ trợ # làm nhận xét hoặc bỏ qua dòng đầu tiên cần phải trải qua một ngôn ngữ kịch bản khác bỏ qua ngôn ngữ đó.

Điều đó đang được nói bạn có thể có các tập lệnh bash có nội tuyến nhị phân có thể được gọi. Trình cài đặt trò chơi làm như vậy.

+0

Làm thế nào để bạn sử dụng một đốm màu nhị phân trong một tập lệnh bash? –

+0

ví dụ: http://www.linuxjournal.com/content/add-binary-payload-your-shell-scripts – Alex

2

Thay vì viết nhiều mã để Java có thể thực thi dưới dạng nguồn, bạn có một vài tùy chọn:

Sử dụng Scala! Bạn có biết rằng Scala được xây dựng trên Java không? Nó có một thông dịch viên và trình biên dịch. Bạn có thể chạy một kịch bản, một trình bao hoặc biên dịch và chạy nó. Scala và Java làm việc liền mạch với nhau. Cả hai biên dịch sang cùng một bytecode và chạy trên một JVM. Có, ngôn ngữ sẽ cảm thấy kỳ lạ bởi vì Scala giống như một chéo giữa Java, R và Python, nhưng hầu hết các ngôn ngữ cốt lõi là không thay đổi và tất cả các gói Java có sẵn. Hãy thử Scala. Nếu bạn đang sử dụng Linux, bạn cũng có thể quan sát Spark, ngay cả đối với một máy.

Nếu bạn nhấn mạnh vào việc chỉ sử dụng Java, bạn có thể tạo chương trình lai thực hiện hai việc (tôi đã thực hiện việc này trước đây): biên dịch mã và chạy nó. Tập lệnh thực thi hoặc thậm chí là một tập lệnh bash có thể thực hiện công việc lấy các tệp nguồn và làm cho chúng có thể thực thi được. Nếu bạn đang muốn tạo một trình bao Java, thì bạn cần tạo một trình biên dịch/trình nạp thời gian động, nhưng bạn chỉ cần sử dụng những gì Java/Oracle đã cung cấp cho chúng ta. Hãy tưởng tượng chèn cú pháp Java từ một tệp mà tôi đặt một câu lệnh in. Bạn có thể có bất cứ điều gì trong đó bạn muốn miễn là nó biên dịch. Xem ví dụ sau:

package util.injection; 

import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.Writer; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.Locale; 
import javax.tools.Diagnostic; 
import javax.tools.DiagnosticCollector; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaFileObject; 
import javax.tools.StandardJavaFileManager; 
import javax.tools.ToolProvider; 

public class Compiler { 

    static final long t0 = System.currentTimeMillis(); 

    public static void main(String[] args) { 
     StringBuilder sb = new StringBuilder(64); 
     String packageName = "util"; 
     String className = "HelloWorld"; 
     sb.append("package util;\n"); 
     sb.append("public class HelloWorld extends " + Function.class.getName() + " {\n"); 
     sb.append(" public void test() {\n"); 
     sb.append("  System.out.println(\"Hello from dynamic function!\");\n"); 
     sb.append(" }\n"); 
     sb.append("}\n"); 
     String code = sb.toString(); 

     String jarLibraryFile = "target/myprojectname.jar"; 

     Function dynFunction = code2class(packageName, className, code, jarLibraryFile); 
     dynFunction.test(); 
    } 

    public static Function code2class(String packageName, String className, String code, String jarLibraryFile) { 
     String wholeClassName = packageName.replace("/", ".") + "." + className; 
     String fileName = wholeClassName.replace(".", "/") + ".java";//"testcompile/HelloWorld.java"; 
     File javaCodeFile = new File(fileName); 
     string2file(javaCodeFile, code); 
     Function dynFunction = null; 
     try { 

      boolean success = compile(jarLibraryFile, javaCodeFile); 

      /** 
      * Load and execute 
      * ************************************************************************************************ 
      */ 
      System.out.println("Running... " + (System.currentTimeMillis() - t0) + " ms"); 
      Object obj = load(wholeClassName); 
      // Santity check 
      if (obj instanceof Function) { 
       dynFunction = (Function) obj; 
       // Run it 
       //Edit: call dynFunction.test(); to see something 
      } 
      System.out.println("Finished... " + (System.currentTimeMillis() - t0) + " ms"); 
     } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) { 
      exp.printStackTrace(); 
     } 
     return dynFunction; 
    } 

    public static boolean compile(String jarLibraryFile, File javaCodeFile) throws IOException { 
     /** 
     * Compilation Requirements 
     * ******************************************************************************************** 
     */ 
     System.out.println("Compiling... " + (System.currentTimeMillis() - t0) + " ms"); 
     DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); 
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); 

     // This sets up the class path that the compiler will use. 
     // I've added the .jar file that contains the DoStuff interface within in it... 
     List<String> optionList = new ArrayList<>(2); 
     optionList.add("-classpath"); 
     optionList.add(System.getProperty("java.class.path") + ";" + jarLibraryFile); 

     Iterable<? extends JavaFileObject> compilationUnit 
       = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(javaCodeFile)); 
     JavaCompiler.CompilationTask task = compiler.getTask(
       null, 
       fileManager, 
       diagnostics, 
       optionList, 
       null, 
       compilationUnit); 
     fileManager.close(); 

     /** 
     * ******************************************************************************************* 
     * Compilation Requirements * 
     */ 
     if (task.call()) { 
      return true; 
      /** 
      * *********************************************************************************************** 
      * Load and execute * 
      */ 
     } else { 
      for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { 
       System.out.format("Error on line %d in %s%n", 
         diagnostic.getLineNumber(), 
         diagnostic.getSource().toUri()); 
       System.out.printf("Code = %s\nMessage = %s\n", diagnostic.getCode(), diagnostic.getMessage(Locale.US)); 

      } 
     } 
     return false; 
    } 

    public static void string2file(File outputFile, String code) { 
     if (outputFile.getParentFile().exists() || outputFile.getParentFile().mkdirs()) { 

      try { 
       Writer writer = null; 
       try { 
        writer = new FileWriter(outputFile); 
        writer.write(code); 
        writer.flush(); 
       } finally { 
        try { 
         writer.close(); 
        } catch (Exception e) { 
        } 
       } 
      } catch (IOException exp) { 
       exp.printStackTrace(); 
      } 
     } 
    } 

    public static Object load(String wholeClassName) throws IllegalAccessException, InstantiationException, ClassNotFoundException, MalformedURLException { 
     // Create a new custom class loader, pointing to the directory that contains the compiled 
     // classes, this should point to the top of the package structure! 
     URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()}); 
     // Load the class from the classloader by name.... 
     Class<?> loadedClass = classLoader.loadClass(wholeClassName); 
     // Create a new instance... 
     Object obj = loadedClass.newInstance(); 
     return obj; 
    } 

} 

..

package util.injection; 

public class Function { 

    private static final long serialVersionUID = 7526472295622776147L; 

    public void test() { 
       System.out.println("Hello from original Function!"); 
    } 

    public int getID() { 
     return -1; 
    } 

    public void apply(float[] img, int x, int y) { 

    } 

    public double dot(double[] x, double[] y) { 
      return 0; 
    } 
} 
Các vấn đề liên quan