Analizador de opciones de línea de comandos para Java

Estoy escribiendo un shell en Java porque no he programado en Java durante demasiado tiempo y lo he olvidado mucho. Iba a escribir el mío propio, pero en este momento me gustaría obtener un prototipo que funcione, por lo que me gustaría incluir un analizador de opciones de línea de comandos existente.

Requisitos:

  • StringToma un o arbitrario String[](es decir, no usa los argumentos de la línea de comando)
  • Toma argumentos en un formato similar a getopt(la versión mejorada de GNU); específicamente:
    • Se pueden unir múltiples opciones de una sola letra (por ejemplo, -a -b -ca -abc)
    • Admite opciones largas (por ejemplo, --message="Hello!") (aunque no tiene que admitir opciones largas de un solo guión)
    • Asume que todos los bits que no son de opción al final son parámetros que se pasan normalmente (por ejemplo -abc --long="Hello!" param1 param2, me dice que los parámetros son param1y param2)
    • --se puede usar para separar las opciones de los argumentos (por ejemplo -ab --custom="hello" -- -file_starting_with_hyphen -another, me da las opciones/indicadores a, by customcon los valores apropiados, y me dice que los argumentos son -file_starting_with_hypheny -another)
    • Los espacios en blanco pueden ser parte de los argumentos, si se citan.
    • Un nombre de opción seguido de un valor se analiza como la opción que tiene ese valor (por ejemplo -h foo, dice que hay una opción h, con un valor, foo)
  • Totalmente multiplataforma
  • No necesita que especifique qué opciones estoy buscando (es decir, le paso un Stringo String[]y me dice qué banderas/opciones se configuraron, en lugar de buscar las opciones que quiero configurar y asumir que el resto son argumentos )
    • Esto significa que no usa anotaciones para especificar dónde almacenar los valores de las banderas . Al menos dos respuestas hasta ahora han hecho esto.
  • Gratis (como en la cerveza)
  • Se puede usar legalmente en cualquier proyecto (es decir, no comercial, no GPL)

Ideal, pero no necesario:

  • Pequeño: un archivo
  • Licencia mínima de derechos de autor ( no copyleft; me gusta no preocuparme por cuestiones legales y odio a las personas que intentan decirme que no puedo usar mi trabajo, sin embargo, muy bien, por favor)
  • Utiliza las interfaces integradas ( java.util.Map, específicamente) para devolver datos. (Esto es para poder escribir mi propia función más fácilmente más adelante)
  • Fuente abierta
@a_horse Si no recuerdo mal, no usé ese porque requiere que especifique qué opciones estoy buscando. Ver los requisitos en la pregunta.
Estoy bastante seguro de que getopt también requiere que especifique los argumentos que está buscando. Y definitivamente permite unir argumentos de un solo carácter, entonces, ¿cómo se diferencia entre "-top" como un argumento largo y la combinación de -t, -o y -p sin especificar qué está permitido? Menciono esto porque " works like getopt" es su segundo requisito.
@CPerkins "me gusta" significa "similar a", aquí, no "precisamente de la misma manera que".
Bien gracias. Nueva pregunta: me parece que la combinación de los "bits que no son de opción al final son parámetros" y "los espacios en blanco están permitidos en los argumentos" es ambigua. ¿Qué pasa si los argumentos terminan con "-n=alpha beta"? ¿Es "beta" parte del valor de n? ¿O es un parámetro?
@CPerkins Quise decir que algo así -n "foo bar baz"se procesaría como el indicador ncon parámetro foo bar baz, en lugar de ncon parámetro "fooy dos argumentos, bary baz".
(Ha pasado un tiempo desde que toqué las cosas de CLI, por lo que podría estar obteniendo "parámetro" y "argumento" al revés. Lo que quiero decir debe quedar claro).
Pero ¿qué pasa -n foo bar baz? Con las comillas, lo que quieres es claro. Supongo que estoy preguntando si los espacios en blanco son siempre un separador.
@CPerkins Allí. Aparte de escribir una especificación técnica completa, eso es toda la especificidad en la que estoy dispuesto a entrar. Puede deducir el resto de cómo funcionan normalmente las opciones de la línea de comandos
Entiendo. Ver respuesta.

Respuestas (4)

Puedes revisar FeSimpleArgs

Creo que cumple con todos tus requisitos:

Concepto: un analizador de línea de comandos muy ligero. Toma argumentos en forma de cadena o cadena [], devuelve una instancia de clase que contiene los argumentos en un mapa y los parámetros en una lista.

Requisitos:

  • Toma un String o String[] arbitrario (es decir, no usa los argumentos de la línea de comando)
  • Toma argumentos en un formato similar a getopt (la versión mejorada de GNU); específicamente:
  • Se pueden unir múltiples opciones de una sola letra (por ejemplo, -a -b -c a -abc)
  • Admite opciones largas (p. ej., --message="¡Hola!") (aunque no es necesario que admita opciones largas de un solo guión)
  • Supone que todos los bits que no son de opción al final son parámetros que se pasan normalmente (por ejemplo, -abc --long="¡Hola!" param1 param2 me dice que los parámetros son param1 y param2)
  • -- se puede usar para separar las opciones de los argumentos (p. ej. -ab --custom="hola" -- -file_starting_with_hyphen -otro me da las opciones/indicadores a, b y custom con los valores apropiados, y me dice que los argumentos son -file_starting_with_hyphen y -other)
  • Los espacios en blanco pueden ser parte de los argumentos, si se citan.
  • Un nombre de opción seguido de un valor se analiza como la opción que tiene ese valor (por ejemplo, -h foo dice que hay una opción, h, con un valor, foo)

  • Totalmente multiplataforma

  • No necesita que especifique qué opciones estoy buscando (es decir, le paso una Cadena o Cadena [] y me dice qué banderas/opciones se configuraron, en lugar de buscar las opciones que quiero configurar y asumir el resto son argumentos) Si

en cuanto al uso:

  • Gratis (como en la cerveza) Sí - Apache 2.0
  • Se puede usar legalmente en cualquier proyecto (es decir, no comercial, no GPL) Sí - Apache 2.0
  • Licencia mínima de derechos de autor (no copyleft; me gusta no preocuparme por problemas legales y odio a la gente que intenta decirme que no puedo usar mi trabajo, sin embargo, lo hago muy bien, por favor) Sí - Apache 2.0

Publicado bajo licencia Apache 2.0.

Ideal, pero no necesario:

  • Pequeño: un archivo (un archivo para el analizador, uno para las pruebas unitarias, no es necesario para analizar)
  • Utiliza las interfaces integradas (java.util.Map, específicamente) para devolver datos. (Esto es para poder escribir mi propia función más fácilmente más adelante) ** Más o menos ** (Devuelve una clase que contiene un java.util.Map de argumentos y una Lista de parámetros)

USO Uso: 1) Construya una instancia de FeSimpleArgs

FeSimpleArgs parser = new FeSimpleArgs();

2) Úselo para analizar sus argumentos:

FeSimpleArgs.Result result = parser.parse ("-def=value1 --GHI=value2 -a -b -c=value3 -n=\"foo bar baz\" -- param1 -param2"); 

3) Examine sus resultados: De lo anterior, el resultado consistirá en un Mapa que contiene los siguientes argumentos y banderas (tenga en cuenta que no hay un significado real para "argumento" o "bandera", solo estoy usando esos términos para separar si toman valores o no - todos están en el mismo Mapa).

  • a
  • b
  • d
  • mi
  • f con valor=valor1
  • GHI con valor=valor2
  • c con valor=valor3
  • n con value=foo bar baz (se eliminan las comillas)

Y una lista que contiene estos parámetros (tenga en cuenta que se conserva el guión inicial) - param1 - -param2

4) ¿Beneficio?

Para ver otros ejemplos, consulte las pruebas unitarias incluidas.

Descargo de responsabilidad: soy el autor de FeSimpleArgs

Esto parece perfecto, gracias! Sin embargo, una cosa; con solo echar un vistazo al código, veo algunas cosas que están apagadas, repetidamente compile, Patternque nunca cambian, que tokenize2nunca se usan, etc. Es posible que desee publicar una pregunta en CodeReview.SE .
Buenas observaciones. Tokenize2 estaba destinado a ser un intento de usar una expresión regular diferente. El que ahora no hace lo que realmente me gustaría, que es extraer toda la cadena citada, incluso cuando hay cosas antes. Y no me gusta tener que quitar las comillas. Podría decirse que todavía es un trabajo en progreso, pero incluso en su estado imperfecto, pasa todas las pruebas.

He usado args4j con éxito en varios proyectos. Fue desarrollado por Kohsuke Kawaguchi , quien también desarrolló Jenkins, fue el desarrollador principal de JAXB y otros proyectos, por lo que tiene un muy buen pedigrí.

Creo que lo expresé mal en la pregunta, pero estoy buscando algo a lo que pueda pasar String[]y recuperar (por ejemplo) una Mapde opciones, no algo que analice y asigne automáticamente las opciones de los argumentos dados al archivo jar. . Además, tiene que poder decirme qué opciones se han pasado con qué argumentos, en lugar de que yo le diga qué opciones buscar.

Nota: esta respuesta está desactualizada, porque OP editó la pregunta para agregar un requisito que esto no cumple (sin embargo, todavía es muy bueno saberlo). Vea los comentarios a continuación. El OP NO quiere que vote negativamente esta respuesta.

El clásico para esto en Unix/Linux, desde los días de C, era GetOpt().

Gnome tiene un puerto Java aquí .

Estaba buscando algo menos basado en el estado (¿creo que esa es la palabra? Es decir, una función que devuelve un Mapa, en lugar de escanear). Además, un requisito que olvidé poner es que debe poder extraer cualquier opción arbitraria de la cadena, no solo las que especifique, ya que esto será pasar argumentos para cada comando y analizar los argumentos para cada uno tomaría demasiado tiempo. Aún así, me gusta, aunque solo sea porque puedo revisar su código para ver cómo lo hicieron.
Será mejor que actualice su pregunta para ese requisito que olvidó, para que la gente pueda ayudarlo. ¡Feliz estriado! Espero que esto te haya ayudado un poco :-)
Lo acabo de hacer :D y como dije, ayudó. ¡Gracias!
Y ahora que mi respuesta ya no se aplica, estoy siendo rechazado por personas que no se atreven a leer todo. Así es la vida :-(
Oh, maldita sea. Lo lamento. Podría valer la pena editarlo porque esto se escribió antes de que se agregaran un par de requisitos.
No te preocupes por eso. No estoy aquí por los puntos :-) Si te gustó la respuesta de Stefan, acéptala. También es perfectamente aceptable publicar su propia respuesta y aceptarla. El objetivo es ayudar a futuros buscadores después de lo mismo.
El problema con Stefan es que me gustaría algo que pueda incluir fácilmente, mientras que la CLI de Apache toma como catorce clases y media docena de líneas de código solo para analizar algo que podría hacerse fácilmente con un solo método que toma una Stringy una enumeración. , o un Predicate<T>, o algo así.
Bueno, asegúrese de publicar su respuesta aquí para ayudar a otros. Si codifica algo, considere usar FOSS y publicarlo en GitHub.
No tengo una respuesta, ese es el problema. Sin embargo, he estado buscando uno, y escribir el mío hasta ahora no ha terminado tan mal.
estamos esperando - con gran expectación :-)

picoclí puede ser de su interés. Es un archivo de origen único para animar a los autores de aplicaciones de línea de comandos a incluirlo como fuente como una alternativa más sencilla a sombrear jars en un uberjar. También cumple con todos los demás requisitos establecidos en OP - ACTUALIZACIÓN: excepto por el requisito de que las opciones no se pueden corregir en tiempo de compilación :-(.

ACTUALIZACIÓN 2: picocli 3.x ofrece una API programática además de la API de anotaciones, por lo que ahora cumple con todos los requisitos. Tenga en cuenta que Groovy CliBuilder se basa en picocli desde Groovy 2.5. Esto es exactamente lo que pide el OP: agregar dinámicamente opciones y parámetros posicionales a un comando.

Recientemente agregó la funcionalidad de autocompletar.

Otra característica que te puede gustar es su ayuda de uso coloreada.

Ayuda de uso mínimo con colores ANSI

Características del analizador:

  • API de anotación: el análisis es una línea de código en su aplicación
  • API programática: todo lo que es posible con las anotaciones se puede hacer mediante programación
  • Todo fuertemente tipado: opciones de línea de comando, así como parámetros posicionales
  • Opciones cortas agrupadas de POSIX ( <command> -xvfInputFileasí como <command> -x -v -f InputFile) y opciones largas de GNU
  • Un modelo de aridad que permite un número mínimo, máximo y variable de parámetros, por ejemplo, "1..*","3..5"
  • Subcomandos (se pueden anidar a una profundidad arbitraria)
  • Funciona con Java 5 y superior

El mensaje de ayuda de uso es fácil de personalizar con anotaciones (sin programación). Por ejemplo:

Mensaje de ayuda de uso extendido( fuente )

No pude resistir agregar una captura de pantalla más para mostrar qué mensajes de ayuda de uso son posibles. La ayuda de uso es la cara de su aplicación, ¡así que sea creativo y diviértase!

demostración de picoclí

Descargo de responsabilidad: creé picocli. Comentarios o preguntas muy bienvenidos.

No estoy seguro de que hayas leído mi pregunta por completo. Por favor, asegúrese de leer todos los requisitos.
Gracias por aclarar la pregunta. Debo haberlo perdido en mi entusiasmo.
Sin preocupaciones. Parece una excelente opción para un analizador de línea de comandos regular, pero si eso es lo que quería, dudo que hubiera tenido que hacer una pregunta; hay un montón de opciones por ahí.
Comprendido. Gracias por los comentarios positivos. He actualizado mi respuesta para resaltar que no es una buena combinación. Esperando que siga siendo una respuesta útil para otros lectores ...
Tenga en cuenta que desde picocli 3.x, picocli ofrece una API programática además de la API de anotaciones. Esto cumple con todos los requisitos del OP. Un ejemplo notable es Groovy CliBuilder: desde Groovy 2.5, CliBuilder se implementa con la API programática picocli.