2016-02-25 34 views
5

Dla jasności, przez wykonywalny nie mam na myśli dosłownych bajtów gotowych na procesor. Na przykład skrypt bash, który jest interpretowany, a nie wykonywalny, staje się wykonywalnym, gdy do góry dodawany jest shebang, który określa, że ​​skrypt powinien być uruchamiany przez /bin/bash lub /bin/sh lub jakikolwiek program będzie interpretował go.Czy można wykonać dowolny język wykonywalny?

Zastanawiam się, czy można zrobić to samo z innymi językami skryptowymi? A jeśli tak, to czy jest naprawdę tak proste, jak dodanie shebangu, który odwołuje się do programu do tłumaczenia (tj. #!/usr/bin/python dla skryptu Python lub #!/usr/local/bin/node dla JavaScript)?

Zastanawiam się również, czy można zrobić z Javą, która nie jest technicznie językiem skryptowym, ale zdecydowanie nie jest wykonywalna. Wygląda na to, że Java będzie trudna, ponieważ użytkownik nie ma możliwości dodania shebangu do skompilowanego pliku.

Odpowiedz

3

Można oczywiście stworzyć plik:

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

Można to zrobić z Java

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

Ahh tak z Java pliki .class będą musiały być przechowywane w innym miejscu i odwołuje wykonywalnego jeszcze? –

+0

Tak, to prawda, a przed uruchomieniem tej opcji musisz się upewnić, że ścieżka klas jest poprawna. Dlatego bardziej praktyczne jest używanie skryptu sh. –

+0

To interesujące. Nie wiedziałem, że potrafisz przekazywać argumenty po shebangu.Sądzę, że to jest to, co dostaję za bycie samoukiem haha. Odpowiedź zatwierdzona! –

2

Nie, to nie jest możliwe, aby umieścić huk she na każdym skrypcie i będzie wykonywał. Bash opiera się na fakcie, że plik z shebangiem ignoruje linie zaczynające się od #. Stąd każdy język skryptowy lub kod bajtowy, który może zignorować pierwszą linię z shebangiem będzie działał.

Jeśli twój język nie obsługuje # jako komentarza lub ignoruje, pierwsza linia musi przejść przez inny język skryptowy, który to ignoruje.

Można powiedzieć, że można mieć skrypty bash, które mają wbudowane binarne obiekty typu blob, które można wywoływać. Instalatorzy gier to robią.

+0

W jaki sposób używasz binarnego obiektu typu blob w skrypcie bash? –

+0

na przykład http://www.linuxjournal.com/content/add-binary-payload-your-shell-scripts – Alex

2

Zamiast pisać dużo kodu Java mają być wykonywalny w postaci źródłowej, masz kilka opcji:

Zastosowanie Scala! Czy wiesz, że Scala jest zbudowana na Jawie? Ma interpreter i kompilator. Możesz uruchomić skrypt, powłokę lub skompilować i uruchomić go. Scala i Java współpracują ze sobą bezproblemowo. Obie kompilują się do tego samego kodu bajtowego i działają na maszynie JVM. Tak, język będzie dziwny, ponieważ Scala jest jak skrzyżowanie Javy, R i Pythona, ale większość podstawowego języka pozostaje niezmieniona i wszystkie pakiety Java są dostępne. Wypróbuj Scalę. Jeśli korzystasz z Linuksa, równie dobrze możesz spojrzeć na Sparka, nawet na jeden komputer.

Jeśli nalegasz na używanie tylko Java, możesz stworzyć hybrydowy program, który robi dwie rzeczy (robiłem to wcześniej): skompiluj kod i uruchom go. Skrypt wykonywalny, a nawet bash może wykonywać pracę polegającą na pobieraniu plików źródłowych i wykonywaniu ich. Jeśli szukasz powłoki Java, musisz utworzyć dynamiczny kompilator/program ładujący, ale musisz po prostu użyć tego, co już daje nam Java/Oracle. Wyobraź sobie wstawianie składni Java z pliku, w którym umieściłem instrukcję print. Możesz mieć wszystko, co chcesz, tak długo jak się kompiluje. Zobacz poniższy przykład:

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; 
    } 
} 
Powiązane problemy