Search code examples
javacommand-line-toolapache-commons-clijlinejline2

Java Command-Line App with own prompt


I'm writing a JAVA-Console-Application. After the user started the jar he should get a Commandline like the Linux shell, where he can enter commands. This is something I never programmed before. Normaly im writing GUI's or I start the jar with some Arguments which are parsed.

Basicly I have 2 Questions:

  1. Is there a third-party-libary which helps reading the user-input from the command line parsing the commands and generating the prompt? To parse args passed in the main class I normally use by Apache Commons CLI. Is it use full here, too or is there a better way?
  2. Is there a best practice to provide an "infinite input"? All solutions I found are 10 or more years old like:

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    while(true){
        System.out.print("Enter String");
        String s = br.readLine();
    }
    

    Is this still best practice or is there a better way today?


Solution

  • I am using the library jline2, i.e. with this it's as simple as:

        InputStream inStream = new FileInputStream(FileDescriptor.in);
        ConsoleReader reader = new ConsoleReader("App", inStream, System.out, null);
    
        reader.setPrompt("> ");
    
        reader.addCompleter(new FileNameCompleter());
        reader.addCompleter(new StringsCompleter(Arrays.asList(new String[] {
                "cmd1",
                "exit",
                "quit",
        })));
    
        String line;
        PrintWriter out = new PrintWriter(reader.getOutput());
    
        while ((line = reader.readLine()) != null) {
            if (line.startsWith("cmd1")) {
                String[] cmd = line.split("\\s+");
                if(cmd.length < 2) {
                    out.println("Invalid command");
                    help(out);
                } else {
                    ... do work
                }
            } else if (line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("exit")) {
                break;
            } else {
                help(out);
            }
        }
    
        // ensure that all content is written to the screen at the end to make unit tests stable
        reader.flush();