views:

260

answers:

5

Similar to this thread for C#, I need to split a string containing the command line arguments to my program so I can allow users to easily run multiple commands. For example, I might have the following string:

-p /path -d "here's my description" --verbose other args

Given the above, Java would normally pass the following in to main:

Array[0] = -p
Array[1] = /path
Array[2] = -d
Array[3] = here's my description
Array[4] = --verbose
Array[5] = other
Array[6] = args

I don't need to worry about any shell expansion, but it must be smart enough to handle single and double quotes and any escapes that may be present within the string. Does anybody know of a way to parse the string as the shell would under these conditions?

NOTE: I do NOT need to do command line parsing, I'm already using joptsimple to do that. Rather, I want to make my program easily scriptable. For example, I want the user to be able to place within a single file a set of commands that each of which would be valid on the command line. For example, they might type the following into a file:

--addUser admin --password Admin --roles administrator,editor,reviewer,auditor
--addUser editor --password Editor --roles editor
--addUser reviewer --password Reviewer --roles reviewer
--addUser auditor --password Auditor --roles auditor

Then the user would run my admin tool as follows:

adminTool --script /path/to/above/file

main() will then find the --script option and iterate over the different lines in the file, splitting each line into an array that I would then fire back at a joptsimple instance which would then be passed into my application driver.

joptsimple comes with a Parser that has a parse method, but it only supports a String array. Similarly, the GetOpt constructors also require a String[] -- hence the need for a parser.

+7  A: 
fuzzy lollipop
JSAP is the first parser I've seen to accept a string but, unfortunately, it returns a `JSAPResult` rather than a `String[]`, so I won't be able to use it without switching my command line parsing library :(.
Kaleb Pederson
a `String[]` is pretty useless, the entire reason for JSAP result is it does all the parsing and rules enforcement and checking for you. I think if you really step back from where you are some rethinking of your approach and some refactoring will really be beneficial. See my update based on your last edit.
fuzzy lollipop
I don't want to build a shell string parser. `line.split(" ")` isn't nearly intelligent enough. It would die on the parameter that creates `Array[3]` as I indicated in my post as parameters may have both spaces and escape sequences within them. I need a full parser to handle all the possibilities -- but I need a string to String[] parser, rather than a command line parser.
Kaleb Pederson
JSAP might take a couple of goes at reading through the docs to understand the options it supplies, but it's a very good solution for command-line parsing requirements and works well - definitely recommended...
Gwyn Evans
maybe switching is the best thing you can do joptsimple is probably too "simple" for your requirements.
fuzzy lollipop
A `String[]` is extremely useful to me as I already have a `joptsimple` command line parser that handles all the commands that would be issued within my file. I need only to convert the string into a `String[]` in order to be able to provide easy scripting of multiple commands.
Kaleb Pederson
JSAP's `CommandLineTokenizer` is very close to what I need (and may be sufficient). It parses the string like Windows 2000 instead of like a Unix shell.
Kaleb Pederson
Switching that little bit of code to JSAP will be much less work than writing an ANTLR grammar to parse a UNIX style command line :-)
fuzzy lollipop
A: 

I guess this one will help you:

CLI

InsertNickHere
this is old and busted and a terrible suggestion, there are at least 3 newer supported and non-buggy full featured alternatives to this, don't use this.
fuzzy lollipop
@fuzzy Good to know. But downvoting was not neccessary since this answer is correct though. ;-)
InsertNickHere
bad advice is worse than no advice :-(
fuzzy lollipop
@fuzzy - the suggestion is not old, busted and terrible. This sounds more like your personal opinion about CLI. And the [change reports[(http://commons.apache.org/cli/changes-report.html) show that it is still maintained. So what are your concerns?
Andreas_D
@fuzzy, calm down please and provide some details.
Andreas_D
JSAP, args4j and jewelCLI and others are way better alternatives that are much more flexible less buggy and easier to extend. that apache.commons.cli has a terrible procedural API interface, just about anything else is better that that cli implementation.
fuzzy lollipop
+1  A: 

I use the Java Getopt port to do it.

Andy
Unless I've missed something, the getopt port doesn't take in a string, only a `String[]`.
Kaleb Pederson
A: 

Check out Apache Commons CLI http://commons.apache.org/cli/

or JOpt http://jopt-simple.sourceforge.net/index.html

a_horse_with_no_name
+2  A: 

Here is a pretty easy alternative for splitting a text line from a file into an argument vector so that you can feed it into your options parser:

This is the solution:

public static void main(String[] args) {
    String myArgs = Commandline.translateCommandline("-a hello -b world -c \"Hello world\"");
    for (String arg:myArgs)
        System.out.println(arg);
}

The magic class Commandline is part of ant. So you either have to put ant on the classpath or just take the Commandline class as the used method is static.

Andreas_D
As documentation, `translateCommandline` handles both single and double quoted strings and escapes within them but does not recognize backslash in the same way as a POSIX shell because of problems that causes on DOS based systems.
Kaleb Pederson
There is a source distribution of ant. At this point I'd take the implementation of `translateCommandline` and modify it to fit my needs.
Andreas_D