Mientras desarrollaba la aplicación, comencé a preguntarme: ¿cómo debo diseñar argumentos de línea de comandos?
Muchos programas están usando fórmulas como esta -argument value
o /argument value
. La solución que se me ocurrió fue argument:value
. Pensé que era bueno porque sin espacios en blanco no hay forma de que los valores y los argumentos puedan confundirse. También es fácil dividir una cadena en dos en el primero desde el :
carácter izquierdo .
Mis preguntas son:
- ¿Es la
-argument value
fórmula popular mejor queargument:value
(más legible, más fácil de escribir, libre de errores, más fácil de entender por los desarrolladores expertos)? - ¿Hay algunas reglas comúnmente conocidas que debería seguir al diseñar argumentos de línea de comandos (aparte de si funciona, está bien)?
Pidió algunos detalles más, lo proporcionaré. Sin embargo, creo que no deberían afectar las respuestas. La pregunta es sobre buenos hábitos en general. Creo que son todos iguales para todo tipo de aplicaciones.
Estamos trabajando en una aplicación que se utilizará en lugares públicos (tótems táctiles, tablas). Las aplicaciones se escriben usando Qt Quick 5 (C ++, QML, JS). Los dispositivos tendrán Windows 8.1 / 10 instalado. Proporcionaremos una interfaz frontal para administrar los dispositivos. Sin embargo, algunos administradores avanzados pueden querer configurar la aplicación por su cuenta. No es muy importante desde el lado del negocio, pero como estoy de acuerdo con lo que dijo Kilian Foth , no quiero que mi aplicación sea una molestia para un usuario. No encontré en Internet lo que quiero, pregunté aquí.
Para usuarios más avanzados de Stack Exchange: quería que esta pregunta fuera general. Tal vez califica para el wiki de la comunidad (no sé si la pregunta existente se puede convertir con respuestas). Como quiero que esta pregunta sea independiente del sistema operativo y del lenguaje de programación, las respuestas que aparecen aquí pueden ser una valiosa lección para otros desarrolladores.
fuente
ls -ltr
para combinar las opciones-l
,-t
y-r
. Los programas de estilo GNU también suelen permitir opciones basadas en palabras con un guión doble como en--reverse
lugar de-r
. Hay otras convenciones populares como-h
mostrar ayuda,--
señalar el final de las opciones, especificar-
un nombre de archivo para permitir la lectura de stdin, etc.-argument value
no-argument:value
son comunes. Comunes son-a value
,-avalue
y--argument=value
.getopt(s)
) donde pueda.Respuestas:
En los sistemas POSIX (p. Ej., Linux, MacOSX), al menos para los programas posiblemente iniciados en un terminal de shell (p. Ej., La mayoría de ellos), recomendaría usar las convenciones de codificación de GNU (que también enumeran nombres de argumentos comunes) y consultar las pautas de utilidades POSIX , incluso para software propietario:
siempre maneja
--version
y--help
(¡incluso los/bin/true
acepta!). ¡Maldigo a los autores del software que no entienden--help
, los odio (porqueprog --help
es el primer comando que estoy probando en un nuevo programa)! A menudo--help
se puede abreviar como-h
Haga que el
--help
mensaje enumere todas las opciones (a menos que tenga demasiadas de ellas ... en ese caso enumere las más comunes y consulte explícitamente algunaman
página o alguna URL) y los valores predeterminados de las opciones, y quizás importantes (y específicos del programa ) Variables de entorno. Mostrar estas listas de opciones en el error de argumento de opción.aceptar
-a
el argumento corto (de una sola letra) y tienen algún equivalente--long-argument
, por lo que-a2
--long-argument=2
,--long-argument 2
; por supuesto, podría tener (para opciones poco utilizadas) algún--only-long-argument
nombre; para argumentos modales sin opciones adicionales-cf
generalmente se maneja como-c -f
, etc., por lo que su-argument:value
propuesta es extraña, y no recomiendo hacerlo.use GLIBC getopt_long o mejor (por ejemplo , argp_parse , en OCaml es un
Arg
módulo , ...)a menudo se usa
-
para entrada o salida estándar (si no puede hacerlo, maneje/dev/stdin
e/dev/stdout
incluso en los pocos sistemas operativos que no los tienen)imitar el comportamiento de programas similares reutilizando la mayoría de sus convenciones de opciones; en particular
-n
para funcionamiento en seco (à lamake
),-h
para ayuda,-v
para verbosidad, etc.utilizar
--
como separador entre opciones y archivo u otros argumentossi su programa usa
isatty
para probar que stdin es un terminal (y se comporta "interactivamente" en ese caso), proporcione una opción para forzar el modo no interactivo, del mismo modo si su programa tiene una interfaz GUI (y pruebagetenv("DISPLAY")
en el escritorio X11) pero también podría ser utilizado en lote o línea de comando.Algunos programas (p
gcc
. Ej. ) Aceptan listas de argumentos indirectos, por@somefile.txt
lo que significa leer los argumentos del programasomefile.txt
; Esto podría ser útil cuando su programa acepte una gran cantidad de argumentos (más que los de su núcleoARG_MAX
)Por cierto, incluso podría agregar algunas instalaciones de autocompletar para su programa y shells habituales (como
bash
ozsh
)Algunos comandos antiguos de Unix (por ejemplo
dd
, o inclusosed
) tienen argumentos de comando extraños para compatibilidad histórica. Recomendaría no seguir sus malos hábitos (a menos que esté haciendo una mejor variante de ellos).Si el software es una serie de programas de línea de comandos relacionados, tomar la inspiración de GIT (que utiliza tanta seguridad como una herramienta de desarrollo), que acepta
git help
ygit --help
y tienen muchosgit
subcommand
ygit
subcommand
--help
En casos excepcionales, también puede usar
argv[0]
(mediante el uso de enlaces simbólicos en su programa), por ejemplo,bash
invocado ya querbash
tiene un comportamiento diferente ( shell restringido ). Pero generalmente no recomiendo hacer eso; podría tener sentido si su programa pudiera usarse como un intérprete de script usando shebang, es decir,#!
en la primera línea interpretada por execve (2) . Si haces tales trucos, asegúrate de documentarlos, incluso en los--help
mensajes.Recuerde que en POSIX la cáscara se globbing argumentos ( antes de ejecutar el programa!), Así que evite que requieren caracteres (como
*
o$
o~
) en las opciones que necesitan ser cáscara escapado.En algunos casos, puede incorporar un intérprete como GNU guile o Lua en su software (evite inventar su propio lenguaje de script completo de Turing si no es experto en lenguajes de programación). Esto tiene profundas consecuencias en el diseño de su software (¡por lo tanto, debe pensarlo pronto!). Entonces debería poder pasar fácilmente algún guión o alguna expresión a ese intérprete. Si adopta ese enfoque interesante, diseñe su software y sus primitivas interpretadas con cuidado; podrías tener algún usuario extraño que codifique grandes scripts para tu cosa.
En otros casos, es posible que desee permitir que sus usuarios avanzados carguen su complemento en su software (utilizando técnicas de carga dinámica a la
dlopen
&dlsym
). Nuevamente, esta es una decisión de diseño muy importante (así que defina y documente la interfaz del complemento con cuidado), y deberá definir una convención para pasar las opciones del programa a estos complementos.Si su software es algo complejo, haga que acepte algunos archivos de configuración (además o reemplazo de los argumentos del programa) y probablemente tenga alguna forma de probar (o simplemente analizar) estos archivos de configuración sin ejecutar todo el código. Por ejemplo, un agente de transferencia de correo (como Exim o Postfix) es bastante complejo, y es útil poder ejecutarlo "a medias" (por ejemplo, observar cómo maneja alguna dirección de correo electrónico dada sin enviar un correo electrónico).
Tenga en cuenta que
/option
es una cosa de Windows o VMS. Sería una locura en los sistemas POSIX (porque la jerarquía de archivos se usa/
como un separador de directorio y porque el shell hace el globing). Toda mi respuesta es principalmente para Linux (y POSIX).PD: Si es posible, convierta su programa en un software gratuito , obtendrá mejoras de algunos usuarios y desarrolladores (y agregar una nueva opción de programa es a menudo una de las cosas más fáciles de agregar a un software gratuito existente). Además, su pregunta depende mucho de la audiencia prevista : un juego para adolescentes o un navegador para la abuela probablemente no necesite el mismo tipo y cantidad de opciones que un compilador, o un inspector de red para los administradores de centros de datos, o un software CAD para microprocesador arquitectos o para diseñadores de puentes. Un ingeniero familiarizado con la programación y las secuencias de comandos probablemente le guste mucho más tener muchas opciones ajustables que su abuela, y probablemente quiera ejecutar su aplicación sin X11 (tal vez en un
crontab
trabajo).fuente
git
es un mejor ejemplo. No le recomiendo incluso mirando haciacvs
en el año 2016.dd -h
.--help
por regla general, pero a menudo no reconocen-h
cuál es molesto. Normalmente escribo -h cuando olvido una opción de un programa, es molesto tener que volver a escribir el comando con la opción más larga--help
. Después de todo, escribí -h porque olvidé algo. ¿Por qué se debe esperar que el usuario recuerde qué programas requieren '--help' y qué programas requieren '-h' para mostrar la pantalla de ayuda? Solo incluya una opción para -h y --help.El hecho de que una convención de formato de datos sea popular es su ventaja.
Puede ver fácilmente que usar = o: o incluso '' como separador son diferencias triviales que la computadora podría convertir entre sí con poco esfuerzo. Lo que sería un gran esfuerzo para un ser humano es recordar "Ahora vean, ¿este programa de uso poco frecuente delimitó las cosas con
:
o con=
? Hmmm ..."En otras palabras, por amor a Dios, no te desvíes de las convenciones extremadamente arraigadas sin una razón convincente. La gente recordará su programa como "el que tiene la sintaxis cmdline extraña y molesta" en lugar de "el que salvó mi ensayo universitario".
fuente
dd
utiliza unakey=value
sintaxis. La razón de esta decisión de diseño es que esta herramienta (apodo: d ata d estroyer) puede causar mucho daño cuando se usa incorrectamente. Al obligar al usuario a abandonar su hábito habitual, lo obligan a pensar más detenidamente sobre lo que está haciendo.dd
? Creo que simplemente fue codificado en un momento (¿1970?) Cuando el ARG_MAX del kernel era pequeño, los shells no tenían autocompletados y--long-arguments
no existían. Desde entonces, mejoródd
siendo compatible con versiones anterioresdd
se originó en otro sistema operativo (que no sea UNIX), un lenguaje de scripting (JCL) en el sistema operativo OS / 360 de IBM, donde las convenciones eran diferentes, antes de ser transportadas más o menos sin cambios a UNIX, en parte porque aquellos que probablemente lo usarían, lo sabían por sistema anteriorEn términos simples
Cuando fueres haz lo que vieres.
-p value
o--parameter value
convención. Linux tiene herramientas para analizar dichos parámetros y marcas de una manera fácil.Usualmente hago algo como esto:
Si su aplicación CLI está diseñada para Windows, entonces use
/flag
y/flag:value
convenciones.Sin embargo, algunas aplicaciones como Oracle no usan ninguno. Utilidades de Oracle
PARAMETER=VALUE
.Una cosa que me gusta hacer es, además de aceptar parámetros en la línea de comandos, proporcionar la opción de usar un parfile , que es un archivo de pares clave-valor para evitar largas cadenas de parámetros. Para eso, debe proporcionar un
--parfile mifile.par
parámetro adicional . Obviamente, si--parfile
se usa, todos los demás parámetros se descartan a favor de lo que hay dentro del archivo.Una sugerencia adicional es permitir el uso de algunas variables de entorno personalizadas , por ejemplo, establecer la variable de entorno
MYAPP_WRKSPACE=/tmp
haría innecesario establecer siempre--wrkspace /tmp
.TAB
y luego Shell lo completará por ellos.fuente
gcc
) manejan@mifile.par
como sus--parfile mifile.par
sugerencias.fooCmd -opt1 -opt2 $(cat more_options.opts)
. Por lo tanto, esperaría una opción de "parámetro de archivo de configuración", si se proporciona, básicamente debería funcionar de la misma manera.Una cosa que aún no surgió:
Intente diseñar su software desde los argumentos de la línea de comando hacia arriba. Sentido:
Antes de diseñar la funcionalidad, diseñe la interfaz de usuario.
Esto le permitirá profundizar en casos extremos y casos comunes desde el principio. Por supuesto, aún abstraerá el exterior y el interior, pero dará un resultado mucho mejor que simplemente escribir todo el código y luego cerrar un CLI.
Además, consulte docopt ( http://docopt.org/ ).
docopt es una gran ayuda con eso en muchos idiomas, especialmente para python donde tiene analizadores de argumentos severamente limitados y adversos para el usuario como argparse que todavía se consideran "OK". En lugar de tener analizadores y subparsers y dictados condicionales, simplemente define la ayuda de sintaxis y hace el resto.
fuente
argparse
no ser programador, interfaz de usuario o fácil de usar.Ya se han proporcionado algunos comentarios valiosos (@Florian, Basile), pero permítanme agregar ... OP dice:
Pero también observaciones:
Debe considerar su público objetivo: administradores avanzados . ¿En qué plataforma trabajan normalmente: Win / Unix / Mac? ¿Y en qué plataforma se ejecuta su aplicación? Siga las convenciones de CLI que ya se han establecido para esa plataforma. ¿Sus administradores "avanzados" quieren / necesitan una herramienta basada en GUI?
Desea que la interfaz sea coherente internamente y con otras herramientas de administración. No quiero parar y pensar si es
cmd -p <arg>
ocmd -p:<arg>
ocmd /p <arg>
. ¿Necesito citas porque hay un espacio? ¿Puedocmd -p <val1> <val2>
ocmd -p <val1> -p <val2>
para múltiples objetivos? ¿Son específicos del pedido? ¿Sobrecargable? ¿cmd -p2 <arg> -p1 <arg>
Funciona también? ¿ls -l -r -t dir1 dir2
==ls -trl dir1 dir2
?Para mis herramientas de administración de Unix, siempre he tenido en cuenta la orientación proporcionada por Shelldorado de Heiner junto con las otras referencias mencionadas.
Tan importante como diseñar la CLI es asegurarse de que su aplicación esté diseñada para funcionar con argumentos de línea de comandos de la misma manera que desde la GUI, es decir: no hay lógica de negocios en la GUI o utiliza el comando común llamado desde la GUI y la CLI.
La mayoría de las herramientas administrativas basadas en UNIX en realidad están diseñadas primero como herramientas de líneas de comando y la GUI proporcionada simplemente facilita "llenar" las opciones para la línea de comando. Ese enfoque permite la automatización, el uso de archivos de respuestas, etc. y la administración sin intervención (¡menos trabajo para mí!)
Como conjunto de herramientas clásico utilizado con este enfoque es Tcl / Tk . No sugiero que cambie de herramientas; solo considere primero el enfoque de diseño al escribir una aplicación administrativa basada en GUI como una herramienta de línea de comando; luego coloque la GUI en la parte superior para mayor comodidad. En algún momento, es probable que descubra que la GUI es una tarea difícil (y propensa a errores) si tiene que hacer varias configuraciones y volver a ingresar generalmente las mismas opciones una y otra vez y buscará un enfoque automatizado.
Recuerde que su administrador probablemente tenga que escribir los valores correctos en los cuadros correctos de todos modos, entonces, ¿cuánto esfuerzo está aliviando de todos modos con GUI?
fuente