-
Notifications
You must be signed in to change notification settings - Fork 0
Shell Commands
JNode's command-line environment provides a Bash-like shell experience, implemented entirely in Java, with a custom command framework for parsing arguments and handling I/O redirection.
Unlike Unix, where commands are typically separate executable binaries launched via fork() and exec(), JNode commands are Java classes executed within the same JVM (often within their own Isolates or Proclets).
The shell subsystem handles interactive input, script execution (e.g., jnode.ini), tab-completion, aliasing, and I/O redirection.
Location: shell/src/shell/org/jnode/shell/
The main interactive loop. It reads input from the user (via CommandShellReader), parses it, and executes it using an interpreter.
JNode supports different interpreters.
-
DefaultInterpreter: Simple execution of single commands. -
RedirectingInterpreter: Handles Unix-style pipelines (|) and I/O redirection (>,<). -
bjorne: A Bourne-compatible shell script interpreter capable of running more complex shell scripts.
Decides how the Java class representing the command is run.
-
DefaultCommandInvoker: Runs the command in the current context. -
ThreadCommandInvoker: Runs the command in a newVmThread. -
ProcletCommandInvoker: Runs the command in a new Proclet (a lightweight isolated context sharing the same address space but with separate standard streams and environment variables).
Commands are implemented by extending AbstractCommand (or implementing Command).
public class MyCommand extends AbstractCommand {
private final StringArgument arg = new StringArgument("name", Argument.MANDATORY, "Your name");
public MyCommand() {
super("Prints a greeting");
registerArguments(arg);
}
public void execute() throws Exception {
PrintWriter out = getOutput().getPrintWriter();
out.println("Hello, " + arg.getValue());
}
}JNode commands do not typically parse String[] args manually. Instead, they register Argument objects (e.g., FileArgument, StringArgument, FlagArgument). The shell's syntax parser automatically validates input against these arguments before execute() is called. This also automatically provides --help text and tab-completion.
For detailed information on how the syntax system works, see Syntax.
Commands must be registered to be accessible from the shell. This is done via Plugin Extension Points.
In a plugin's plugin.xml descriptor:
<extension point="org.jnode.shell.aliases">
<alias name="mycmd" class="com.example.MyCommand"/>
</extension>This tells the AliasManager to map the keyword mycmd to the given class. When the user types mycmd, the shell instantiates the class and invokes it.
Many standard Unix-like commands are implemented in shell/src/shell/org/jnode/shell/command/ and cli/src/.
-
File operations:
ls,cp,mv,rm,cat,mkdir -
System info:
free,ps,threads,gc,dmesg -
Network:
ping,ifconfig,route -
Disk:
mount,fdisk,format
Because all commands run in the same JVM, System.out and System.in cannot be safely redirected globally. Instead, commands use getInput(), getOutput(), and getError() provided by AbstractCommand. The Proclet system manages these streams per-thread-group, allowing CommandA | CommandB to work correctly without polluting the global System.out.
-
Plugin-System — How commands are registered via
<alias>extensions. - Code-Conventions — Best practices for writing robust commands.