Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

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
share|improve this question
1  
Does this help? binfmt_misc for java – Mark Plotnick yesterday
    
Yes, that's gonna be it. Thanks. Only getting it up and running is not that easy, alas. – tomas yesterday

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:

share|improve this answer
    
Thanks. I'll take a look. I'm more interested in a solution for the command line though. I just corrected my question, sorry. – tomas yesterday
1  
The first link points to a command-line "run-mailcap" which might be useful. – Thomas Dickey yesterday
    
As you noticed, no real savings. But it gives some insight into the problem. – tomas yesterday

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 http://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), ...

share|improve this answer
    
Thanks. Please see my update to the question. – tomas 11 hours ago
    
@tomas Sorry, I forgot to escape the hex sequences in the magic string. See my edit. – Gilles 10 hours ago
    
Thanks. Something's wrong again. See UPDATE 3. – tomas 10 hours ago
    
I appended the contents of /proc/sys/fs/binfmt_misc/java-class to the last update. – tomas 10 hours ago
    
@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. – Gilles 1 hour ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.