¿Qué se considera la mejor práctica para el uso / ayuda de impresión (--help)?

13

Al escribir herramientas para la CLI de UNIX, ¿cómo debo hacer que el programa imprima ayuda y / o uso?

Usualmente uso fprintf(stderr, "help text here");, pero hay varios problemas con eso.

  • Primero, no estoy seguro de si debo usarlo stderr. ¿Está bien o debería usarlo stdout?
  • Como puede imaginar, el texto de ayuda es bastante largo, dependiendo de cuántas opciones tenga la herramienta. Ahora, por lo general, solo pongo varios "strings like that\n"en el segundo parámetro. Sin embargo, esto llena mi código fuente con cincuenta o más líneas de texto de ayuda. No es fácil de manejar en absoluto. ¿Qué debo hacer en su lugar?
  • Cuando una herramienta no está escrita en C o en un lenguaje similar a C, tiendo a usar documentos aquí donde sea posible (lo más destacado con Perl). No puedo usar eso en C, pero ¿hay algo así que pueda usar?
  • Estaba considerando ponerlo headerfile.hdentro de un #define HELP "help text here", nunca lo he visto en la naturaleza, no sé si realmente debería usar eso.

Idealmente, podría poner el texto en un archivo externo e incluirlo. Sin #includeembargo, usar eso parece estar mal. ¿Que debería hacer entonces?

La idea es, tener un texto de ayuda, que sea fácilmente manejable. Tenerlo dentro del código fuente no es realmente conveniente.

polemon
fuente
1
¿Qué tiene de malo 50 líneas en su código fuente? Solo ponlo al final. No es como si tuviera que meterse con él regularmente.
cuál es
2
Uso de @whatsisname, ayuda para normal y longopts. Termino teniendo alrededor de 200 líneas de cadenas en el código agrio. Aparte de eso, simplemente no creo que esta sea la mejor práctica, etc. Debe haber una forma más eficiente de
incluir

Respuestas:

8

Inspírate con los elementos internos de tu plataforma objetivo

Echa un vistazo al código fuente del BSD. Por ejemplo, aquí están:

  • usage(void)para la /usr/bin/unameherramienta de NetBSD [ fuente ]:

    usage(void)
    {
        fprintf(stderr, "usage: uname [-amnprsv]\n");
        exit(EXIT_FAILURE);
    }
    
  • usage(void)para NetBSD's /usr/bin/telnet[ fuente ]

  • usage(void)para OpenBSD /bin/ls[ fuente ]

Echa un vistazo a las alternativas

Y decide por ti mismo si son mejores o peores. Puede usar Google CodeSearch para buscar otros, como:

Como puede ver, el estilo diferente entre estos y las herramientas integradas de los sistemas BSD enumerados anteriormente. No significa que tengas que seguir a uno u otro. Pero generalmente es bueno mirar a su alrededor y conformarse con la solución consistente.

Una solución no estándar a las 50 líneas de ayuda ...

Si no desea evitar 50 líneas de texto, simplemente puede leer la ayuda de un archivo de texto (en texto plano, o tal vez analizar directamente la manfuente del archivo si creó uno). Sin embargo, creo que es una forma bastante elegante (ya que incluso puede buscar el documento de texto), para programas de sistemas centrales que los harían inherentemente inseguros e introducirían un punto de falla. Otras personas argumentarán que es pesado para un mensaje usageo helpmensaje, pero no es como si se llamaran en bucles rápidos y apretados ...

En caso de duda, sigue a los gigantes.

haylem
fuente
9

Yo uso stdout, porque una ayuda no es un error.

Si esta es una larga ayuda en C, trato de imitar los documentos aquí:

printf("This is the help for MyWonderfulApp\n"
       "Options are:\n"
       "    --help: display what you are reading now\n"
       "    --quiet: output nothing\n");

Pero la mayoría de las veces escribo una manpágina usando nroff -manetiquetas dedicadas. La ayuda en la aplicación simplemente consiste en referirse a esa manpágina.

Mouviciel
fuente
Pero la ayuda no es necesariamente una salida estándar deseable, ¿verdad? ¿Qué tal stdlog?
greyfade
@greyfade: ¿Es el stdlogestándar C?
Mouviciel
@ Mouviciel: ... pensé que era. Supongo que no. C ++ tiene una corriente estándar relacionado ( cin, cout, cerr, y clog), así que supongo que pensé stdlogfue en la norma C. Culpa mía.
greyfade
2

Si estaría usted me acaba de abrir hasta las fuentes de grep, tail, cat, your_other_favorite_unix_shell_commandpara ver cómo se hace allí. Estoy bastante seguro de que sus formas están bastante bien pensadas y que muchas personas pueden mantenerlas.

Sobre stderro stdout. Es realmente simple, si hay un error, escriba a stderr, si es solo información stdout. Por ejemplo, si ejecuto su herramienta con opciones incorrectas, es posible que desee mostrar un error, digamos Use --help for usage, este pertenece stderr. Si ejecuto su herramienta con una opción válida --help, úsela stdout.

Si prefiere no tener cadenas de ayuda largas cerca de su código, no lo haga. #definir en un archivo de encabezado está perfectamente bien, pero es realmente una preferencia personal. Si tuviera que leer el código de una herramienta de línea de comandos, preferiría que su cadena de ayuda esté dentro de un archivo que maneje las opciones proporcionadas por el usuario.

devmiles.com
fuente
2
Eso no responde a su pregunta.
Mavrik
Hm, ¿qué pasa con el menos? ¿Para qué?
devmiles.com
@Mavrik: el primer párrafo sí.
haylem
1

Yo uso la biblioteca gnu getopts . Para ver un ejemplo con ayuda, vea este proyecto de muestra , específicamente el método principal en la parte inferior de parser.y .

Como está envuelto en llaves, el editor vim que uso puede doblar las líneas, y ni siquiera las noto cuando no lo necesito.

Spencer Rathbun
fuente
1

Si uso C o prefiero no depender de las bibliotecas de Boost, me quedo con GNU getopt. De lo contrario, prefiero las Opciones del programa Boost, que imprime la ayuda automáticamente.

También considero adivinar la opción correcta como una de las mejores prácticas cuando se trata del manejo de opciones. Lo aprendí de Git y ahora uso lo mismo en mis proyectos. Básicamente utiliza la distancia Damerau – Levenshtein para imprimir las mejores coincidencias si el usuario ingresa alguna opción de línea de comando desconocida.

Escribí un pequeño artículo sobre esto que puedes usar como ejemplo.

Espero eso ayude :)


fuente
1

Obviamente, escribir una página de agujero en cout << o el código printf () es engorroso, especialmente si necesita cambiar y volver a llenar sus párrafos. Por lo tanto, obviamente es una buena idea editar ese texto en un archivo separado, utilizando, por ejemplo, emacs, donde puede formatear más fácilmente su texto.

Luego puede usar el siguiente script sed para convertir ese archivo de texto en un archivo de encabezado C legal:

s/\"/\\\"/g
s/$/\\n"/
s/^/"/
1i\
const char *helpStr = 
$a\
;

Luego, al #incluir -incluir su archivo de encabezado en su código fuente, simplemente puede escribir su texto usando

cout << helpStr;
usuario29809
fuente