3

It would be handy to be able to start Java programs by just calling the class file from the terminal (and have it running it the terminal when double-clicked in GUI, but this is less important). I so far only help myself with the following ad hoc fix:

alias cs='java charstat.Charstat' 

Linux recognises the files as Java:

 charstat/Charstat.class: compiled Java class data, version 52.0 (Java 1.8) 

So is there a way to have the call hard-wired? Ubuntu 16.04 here, but general answers welcome.


End of the question, troubleshooting section starts.


UPDATE

So far the most promising line of action is the one proposed by Gilles. So I ran:

echo ":java-class:M:0:cafebabe::/usr/bin/java:" | sudo tee /proc/sys/fs/binfmt_misc/register

Now,

tomasz@tomasz-Latitude-E4200:~/Desktop$ cat /proc/sys/fs/binfmt_misc/java-class enabled interpreter /usr/bin/java flags: offset 0 magic 6361666562616265 

But,

tomasz@tomasz-Latitude-E4200:~/Desktop$ ./Void.class bash: ./Void.class: cannot execute binary file: Exec format error 

This was done on Ubuntu 14.04. It has:

binfmt-support/trusty,now 2.1.4-1 amd64 [installed,automatic] Support for extra binary formats 

which I think was not installed automatically on 16.04 if that matters.

Yesterday already, following Mark Plotnick's comment, I wrestled with this guide, to no avail. It introduced a wrapper at /usr/local/bin/javawrapper, which Gilles' solution doesn't contain. That's for Arch Linux though.

UPDATE 2 (Ubuntu 16.06)

On 16.06:

tomasz@tomasz-Latitude-E4200:~/Desktop/io$ cat /proc/sys/fs/binfmt_misc/Java enabled interpreter /usr/local/bin/javawrapper flags: offset 0 magic cafebabe 

And,

tomasz@tomasz-Latitude-E4200:~/Desktop/io$ ./Nain.class bash: ./Nain.class: No such file or directory 

UPDATE 3

After echo ":java-class:M:0:\xca\xfe\xba\xbe::/usr/bin/java:" | sudo tee /proc/sys/fs/binfmt_misc/register :

tomasz@tomasz-Latitude-E4200:~/Desktop/io$ java Main Please input the file location and name. ^Ctomasz@tomasz-Latitude-E4200:~/Desktop/io$ ./Main.class Error: Could not find or load main class ..Main.class 

For the record:

tomasz@tomasz-Latitude-E4200:/proc/sys/fs/binfmt_misc$ cat java-class enabled interpreter /usr/bin/java flags: offset 0 magic cafebabe 
2
  • 1
    Does this help? binfmt_misc for javaCommentedJul 31, 2016 at 22:50
  • Yes, that's gonna be it. Thanks. Only getting it up and running is not that easy, alas.
    – user147505
    CommentedJul 31, 2016 at 23:21

2 Answers 2

4

Linux

Ubuntu already does this for a jar. With the openjdk-8-jre package (and earlier versions), executing a jar invokes jexec on it. This isn't done for a class, maybe because it's rare for a class to be a standalone executable rather than a library (then again, that's also the case for jars).

You can configure the same underlying mechanism to handle classes. That mechanism is the Linux binfmt_misc feature, which allows the kernel to execute arbitrary files via a helper program.

Because Java's command line is really weird, you need to go through a wrapper to convert the file name into something that the java command is capable of executing. Save this script as /usr/local/bin/javarun and make it executable:

#!/bin/sh case "$1" in */*) dir="${1%/*}"; base="${1##*/}";; *) dir="."; base="$1";; esac shift case "$base" in [!-]*.class) base="${base%.*}";; *) echo >&2 "Usage: $0 FILENAME.class [ARGS...]"; exit 127;; esac case "$CLASSPATH" in "") exec java -cp "$dir" "$base" "$@";; *) exec java -cp "$dir:$CLASSPATH" "$base" "$@";; esac 

The following command should to the trick for classes. See https://unix.stackexchange.com/a/21651 and the kernel documentation for explanations.

echo ":java-class:M:0:\xca\xfe\xba\xbe::/usr/local/bin/javarun:" | sudo tee /proc/sys/fs/binfmt_misc/register 

Run this once to enable it. To remove a setting, run sudo rm /proc/sys/fs/binfmt_misc/java-class. Once you're happy with the setting, add the following command to /etc/rc.local:

echo >/proc/sys/fs/binfmt_misc/register ":java-class:M:0:\xca\xfe\xba\xbe::/usr/local/bin/javarun:" 

Zsh

If you use zsh as your shell, you can make it execute files based on their extension, by defining a suffix alias.

alias -s class=javarun 

You need the same javarun script as above. Of course this only works in zsh, not in bash, file managers, scripts (except zsh scripts where this command has run), ...

7
  • @tomas Sorry, I forgot to escape the hex sequences in the magic string. See my edit.CommentedAug 1, 2016 at 14:03
  • I appended the contents of /proc/sys/fs/binfmt_misc/java-class to the last update.
    – user147505
    CommentedAug 1, 2016 at 14:41
  • @tomas Ugh, java. The binfmt_misc part was working, but you can't execute Java class just by running java /path/to/file.class, no. You need a wrapper script. See my edit.CommentedAug 1, 2016 at 23:36
  • Never mind. I didn't set o+x on javarun. Thanks.
    – user147505
    CommentedAug 2, 2016 at 18:00
  • In your script, where from will Bash know the variable $CLASSPATH? Is binfmt setting it?
    – user147505
    CommentedAug 2, 2016 at 18:06
2

You could define a mailcap item for ".class", and persuade your browser (or desktop launcher) to use this.

However, that would be just changing which program you ran to start execution (no real savings). The same is true of desktop launchers.

Further reading:

3
  • Thanks. I'll take a look. I'm more interested in a solution for the command line though. I just corrected my question, sorry.
    – user147505
    CommentedJul 31, 2016 at 20:05
  • 1
    The first link points to a command-line "run-mailcap" which might be useful.CommentedJul 31, 2016 at 20:07
  • As you noticed, no real savings. But it gives some insight into the problem.
    – user147505
    CommentedJul 31, 2016 at 20:38

You must log in to answer this question.