I have written a program in Clojure and I'd like to execute it on the command-line without specifically invoking java on the command-line (such as java -jar
). I want a single executable file, such as myprogram
, that accepts any arguments and runs my program. Here are a couple things that might make this easier:
java
is in the path. I have gotten pretty far down this path with one approach, but I have to wonder if there's a better way.
FOR REFERENCE ONLY: What I've Tried Already
I'll describe my approach below, but any answers don't need to follow this approach at all.
What I have done is create a lein plugin called makescript
that generates an uberjar, base64 encodes it, and places it inside a Ruby script in a so-called heredoc variable, like this:
# ...ruby script...
BASE64_JAR = <<-JAR_BOUNDARY
# [...base64 encoded file here...]
JAR_BOUNDARY
You should then be able to run the ruby script. It will take the BASE64_JAR variable, unencode it, place it in a temporary file, and execute it by invoking java -jar <filename>
.
The problem I'm having with this approach is that Ruby's base64
library and Clojure's clojure.data.codec.base64
libraries seem to be producing different strings to represent the jar, and a string encoded by Clojure does not decode to the original file if I use Ruby. This may have something to do with the encoding of the strings themselves (UTF-8-related? maybe) between the two languages. Here are repl/irb sessions that illustrate the disconnect:
repl=> (def jar-contents (slurp "../target/myproj-0.1.0-SNAPSHOT-002-standalone.jar"))
repl=> (count jar-contents) ;; => 9433328
repl=> (def a-str (String. (clojure.data.codec.base64/encode (.getBytes jar-contents)) "UTF-8"))
repl=> (count a-str) ;; => 23265576
irb> f = File.open("target/pwgen-0.1.0-SNAPSHOT-002-standalone.jar", "r").read()
irb> p f.length # => 9657639
irb> b = Base64.encode64(f)
irb> p b.length # => 13564973
Note the raw sizes are close but not the same, but the encoded versions are much different.
Although this is puzzling and I'd like to know why this happens, I think I can bypass the problem by having makescript just generate the uberjar and pass the path to another Ruby script, which then will base64 encode (and later decode, also using Ruby) the standalone JAR. The question still stands: is there a better, simpler way? Am I missing something obvious, or is this really as hard as it seems?
如果你真的想这样做,你可以对其进行uuencode :在bash可执行的JAR文件(或任何其他二进制文件),请参阅本为例shell脚本中嵌入一个可执行的二进制
It sounds like you're just trying to bootstrap your app from a script using cleaner syntax. This might be most easily done like so:
create a new bash script called myprogram
:
#!/usr/bin/bash
# pass whatever command line args you have down through the script
java -jar myjar.jar
give it execute permissions
chmod +x myprogram
run it
./myprogram (with whatever params)
If you want to get rid of the ./
you'll need to move things around so the script gets picked up by your PATH
.
Keep in mind that you're . 。 Doing so would pretty much defeat the purpose of using the jvm in the first place. You'd just be invoking it through an extra layer of indirection.
What about running clojure as an interpretive script. Create a new file called mytest
:
#!/usr/bin/clojure
(print "hello world")
and then
chmod +x mytest
and then simply run it
./mytest
There are plenty of drawbacks to this. It's really slow to start. This simple 1 liner took over 2 seconds to run! You're only going to get a single file. Probably this is useful only for the most simple things. But this could be useful if you're just trying to do something quickly which isn't production or test something.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.