An interactive shell for picocli applications, built on JLine. Give it a picocli root command and you get:
- an interactive REPL with tab completion, syntax highlighting and persistent history
- one-shot execution when command-line arguments are given
- a small scripting language (
source, variables,if/elif/else,for, command substitution) - a set of built-in commands (
help,set,echo,less,exit, ...)
xishell is extracted from the XiPKI project.
- Java 11 or later
- Maven 3 (to build)
mvn clean install<dependency>
<groupId>org.xipki.shell</groupId>
<artifactId>xishell</artifactId>
<version>7.0.0-SNAPSHOT</version>
</dependency>xishell logs through SLF4J; add an SLF4J binding of your choice to your application.
import org.xipki.shell.Completion;
import org.xipki.shell.PicocliShell;
import org.xipki.shell.ShellBaseCommand;
import org.xipki.shell.completer.FilePathCompleter;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "mytool", subcommands = {MyTool.Hello.class})
public class MyTool {
@Command(name = "hello", description = "Say hello", mixinStandardHelpOptions = true)
static class Hello extends ShellBaseCommand {
@Option(names = "--name", description = "who to greet")
@Completion(values = {"alice", "bob"})
private String name = "world";
@Option(names = "--out", description = "output file")
@Completion(FilePathCompleter.class)
private String out;
@Override
public void run() {
println("Hello, " + name + "!");
}
}
public static void main(String[] args) throws Exception {
// No arguments: interactive shell. With arguments: run them once and exit.
System.exit(PicocliShell.run("mytool> ", new MyTool(), args));
}
}$ mytool
Welcome to mytool 1.0.0
Type 'help' for commands, 'exit' to quit.
mytool> hello --name alice
Hello, alice!
$ mytool hello --name bob
Hello, bob!
| Type | Purpose |
|---|---|
PicocliShell |
Entry point. run(prompt, rootCommand[, args]) starts the shell; an instance also offers executeLine(...), executeScript(...), commandLine() and stop(). |
ShellBaseCommand |
Optional base class for commands, with helpers such as println, readPrompt, readSecret, confirmAction, saveVerbose and toBigInt. |
@Completion |
Annotation on an option or parameter field: static values and/or a CompletionProvider class. |
CompletionProvider |
Interface for dynamic completion candidates. |
completer.FilePathCompleter, completer.DirPathCompleter |
Complete file or directory paths. |
completer.AbstractSetCompleter |
Base class for completers with a fixed set of tokens (strings or enum constants). |
- Completion of subcommands, options and values (from
@Completion). - History is stored in
~/.xipki/<command-name>.history. Values of--passwordand--pinare masked (********) before being written; variable references such as${env:PASSWORD}are kept as they are. - Help:
help [command ...], or-h/--helpon any command. Ctrl-Ccancels the current line;Ctrl-Dleaves the shell.
| Command | Description |
|---|---|
help [command ...] |
Show help for a command |
source <file> [args ...] |
Execute commands from a script file |
set <name> <value> |
Set a shell variable |
unset <name> |
Remove a shell variable |
echo [text ...] |
Print text |
less <file> |
Page through a text file |
sleep <seconds> |
Sleep for the given number of seconds |
clear |
Clear the screen |
java-version [--full] |
Print the Java version |
exception <message> |
Throw an exception with the given message |
return |
Stop executing the current script |
exit, quit |
Exit the shell |
Scripts are run with source <file> [args ...], or from Java with executeScript(...).
A relative script path is resolved against the directory of the calling script (or the
current directory), and then against the shell home given by the system property
org.xipki.shell.home.
# Lines starting with '#' or '//' are comments.
set NAME world
set ITEMS [a b c]
if ${1} eq ""
echo "usage: source demo.sh <count>"
return
fi
if $1 gt 10
echo "big"
elif $1 in 1 2 3
echo "small"
else
echo "medium"
fi
for item in ${ITEMS}
hello --name ${item}
done
set JAVA $(java-version)
echo "Java ${JAVA}, home ${env:HOME}, user ${sys:user.name}"
hello --name ${NAME} \
--out ~/hello.txt- Variables:
$NAME/${NAME}; positional script arguments$1,$2, ...; environment variables${env:NAME}; Java system properties${sys:name}. Escape with a backslash (\${NAME}) to keep the text literal. - Lists:
set X [a b c]. - Conditions (
if/elif):eq,neq,in, and the numeric comparisonsgt,ge,lt,le. Combine alternatives withoror|. - Command substitution:
$(command)is replaced with the command's output. - Line continuation: a trailing
\joins the next line. - Tracing:
set SCRIPT_TRACE trueprints each command before it runs. - Commands that are not shell commands are run as external processes, with the script's directory as the working directory.
- A script that sources itself, directly or indirectly, is rejected.