Qual é a melhor prática considerada para uso / ajuda da impressão (--help)?

12

Ao escrever ferramentas para a CLI do UNIX, como devo fazer com que o programa imprima ajuda e / ou uso?

Eu costumo usar fprintf(stderr, "help text here");, mas há vários problemas com isso.

  • Primeiro, não tenho certeza se devo usar stderr. Está tudo bem ou devo usar stdout?
  • Como você pode imaginar, o texto de ajuda é bastante longo, dependendo de quantas opções a ferramenta possui. Agora, normalmente, basta colocar vários "strings like that\n"no segundo parâmetro. No entanto, isso preenche meu código-fonte com cinquenta ou mais linhas de texto de ajuda. Não é nada fácil de gerenciar. O que devo fazer em vez disso?
  • Quando uma ferramenta não é escrita em C ou em uma linguagem semelhante a C, costumo usar os documentos aqui sempre que possível (principalmente com o Perl). Não posso usar isso em C, mas há algo assim que eu poderia usar?
  • Eu estava pensando em colocá-lo headerfile.hdentro de um interior #define HELP "help text here", nunca o vi na natureza, não sei se devo usá-lo.

Idealmente, eu poderia colocar o texto em um arquivo externo e incluí-lo. Usar #includepara isso parece errado, no entanto. O que devo fazer então?

A idéia é, para ter um texto de ajuda, que seja facilmente gerenciável. Tê-lo dentro do código-fonte não é realmente conveniente.

polemon
fonte
1
O que há de tão ruim em 50 linhas no seu código-fonte? Basta colocar no final. Não é como se você tivesse que mexer com isso regularmente.
Whatsisname
2
@whatsisname use, help for normal and longopts. Acabo tendo cerca de 200 linhas de strings no código fonte. Afora isso, eu só não acho que esta é a melhor prática, etc. Deve haver uma maneira mais eficiente de colocar em textos de ajuda, etc.
Polemon

Respostas:

8

Inspire-se com os elementos internos da sua plataforma de destino

Veja o código fonte do BSD. Por exemplo, aqui estão os:

  • usage(void)para a /usr/bin/unameferramenta do NetBSD [ fonte ]:

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

  • usage(void)para OpenBSD's /bin/ls[ fonte ]

Veja alternativas

E decida por si mesmo se são melhores ou piores. Você pode usar o Google CodeSearch para encontrar outras pessoas, como:

  • Uso do SkyLoad [ fonte ]

Como você pode ver, um estilo diferente entre essas e as ferramentas integradas dos sistemas BSD listados acima. Isso não significa que você deve seguir um ou outro. Mas geralmente é bom olhar em volta e se contentar com a solução consistente.

Uma solução não padrão para as 50 linhas de ajuda ...

Se você não gosta de evitar 50 linhas de texto, pode simplesmente ler a ajuda de um arquivo de texto (em texto sem formatação, ou talvez analisar diretamente a manfonte da fonte, se tiver criado uma). Acho que é uma maneira bastante elegante (como você pode consultar o documento de texto), no entanto, para programas de sistemas principais que os tornariam inerentemente inseguros e apresentariam um ponto de falha. Outras pessoas argumentam que é pesado para uma mensagem usageou help, mas não é como se elas fossem chamadas em loops rápidos e apertados ...

Em caso de dúvida, siga os gigantes.

haylem
fonte
8

Eu uso stdout, porque uma ajuda não é um erro.

Se essa é uma longa ajuda em C, tento imitar os documentos aqui:

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

Mas na maioria das vezes eu escrevo uma manpágina usando nroff -mantags dedicadas. A ajuda no aplicativo consiste simplesmente em se referir a essa manpágina.

mouviciel
fonte
Mas a ajuda não é necessariamente uma saída padrão desejável, é? Que tal stdlog?
greyfade
@greyfade: É stdlogpadrão C?
Mouviciel 5/12
@mouviciel: ... eu pensei que era. Eu acho que não. C ++ tem um fluxo padrão relacionado ( cin, cout, cerre clog), então eu acho que eu pensei stdlogfoi no padrão C. Foi mal.
greyfade
2

Se eu seria você eu apenas abriu fontes de grep, tail, cat, your_other_favorite_unix_shell_commandpara ver como ele é feito lá. Tenho certeza de que seus caminhos são bem pensados ​​e podem ser mantidos por muitas pessoas.

Sobre stderrou stdout. É realmente simples, se houver um erro - escreva para stderr, se for apenas informação - stdout. Por exemplo, se eu executar sua ferramenta com opções erradas, convém exibir um erro, digamos Use --help for usage, em que este pertence stderr. Se eu executar sua ferramenta com uma opção válida --help, use stdout.

Se é sua preferência não ter longas seqüências de ajuda perto do seu código, não. #define em um arquivo de cabeçalho é perfeitamente adequado, mas é realmente uma preferência pessoal. Se eu precisasse ler o código de uma ferramenta de linha de comando, preferiria que sua string de ajuda estivesse dentro de um arquivo que lida com as opções fornecidas pelo usuário.

devmiles.com
fonte
2
Isso não responde a sua pergunta.
Mavrik
Hm, o que há com o menos? Pelo que?
Devmiles.com
@Mavrik: o primeiro parágrafo faz.
21712 haylem
1

Eu uso a biblioteca gnu getopts . Para um exemplo com ajuda, consulte este projeto de amostra , especificamente o método principal na parte inferior de parser.y .

Uma vez que está envolto em chaves, o editor do vim que eu uso pode dobrar as linhas e nem as noto quando não preciso.

Spencer Rathbun
fonte
1

Se eu usar C ou preferir não depender das bibliotecas do Boost, continuo com o GNU getopt. Caso contrário, prefiro as Boost Program Options, que imprimem ajuda automaticamente.

Também considero adivinhar a opção certa como uma das melhores práticas quando se trata de manipulação de opções. Eu aprendi com o Git e agora uso o mesmo em meus projetos. Ele basicamente usa a distância Damerau – Levenshtein para imprimir as melhores correspondências se o usuário digitar alguma opção de linha de comando desconhecida.

Escrevi um pequeno artigo sobre isso que você pode usar como exemplo.

Espero que ajude :)


fonte
1

Obviamente, escrever uma página de furo no código cout << ou printf () é complicado, principalmente se você precisar alterar e preencher novamente seus parágrafos. Portanto, é obviamente uma boa idéia editar esse texto em um arquivo separado, usando, por exemplo, o emacs, onde você pode formatar mais facilmente o seu texto.

Em seguida, você pode usar o seguinte script sed para converter esse arquivo de texto em um arquivo de cabeçalho C legal:

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

Depois, #include - inclua o arquivo de cabeçalho no código-fonte, você pode simplesmente escrever seu texto usando

cout << helpStr;
user29809
fonte