Что считается наилучшей практикой для печати использования / справки (--help)?


13

Когда я пишу инструменты для CLI UNIX, как мне заставить программу распечатывать справку и / или использование?

Я обычно использую fprintf(stderr, "help text here");, но есть несколько проблем с этим.

  • Во-первых, я не уверен, стоит ли мне пользоваться stderr. Это нормально, или я должен использовать stdout?
  • Как вы можете себе представить, текст справки довольно длинный, в зависимости от того, сколько опций у инструмента. Теперь я обычно просто ставлю несколько "strings like that\n"во второй параметр. Это, однако, наполняет мой исходный код пятьдесят или более строк текста справки. Это нелегко сделать вообще. Что я должен сделать вместо этого?
  • Когда инструмент написан не на C или C-подобном языке, я, как правило, использую здесь-документы, где это возможно (особенно заметно на Perl). Я не могу использовать это в C, но есть ли что-то подобное, что я мог бы использовать?
  • Я подумывал о том, чтобы положить его headerfile.hвнутрь #define HELP "help text here", я никогда не видел его в дикой природе, не знаю, стоит ли мне это использовать.

В идеале я мог бы поместить текст во внешний файл и включить его. Использование #includeдля этого кажется неправильным, хотя. Что мне тогда делать?

Идея состоит в том, чтобы иметь справочный текст, которым легко управлять. Иметь его внутри исходного кода не очень удобно.


1
Что плохого в 50 строках исходного кода? Просто поставь это в конце. Это не значит, что вам придется регулярно с ним связываться.
whatsisname

2
Использование @whatsisname, помощь для обычного и длинного опциона. Я заканчиваю тем, что в sourcode есть около 200 строк строк. Кроме того, я просто не думаю, что это лучшая практика и т. Д. Должен быть более эффективный способ
добавления

Ответы:


8

Вдохнови себя внутренностями своей целевой платформы

Посмотрите на исходный код BSD. Например, вот:

  • usage(void)для /usr/bin/unameинструмента NetBSD [ источник ]:

    usage(void)
    {
        fprintf(stderr, "usage: uname [-amnprsv]\n");
        exit(EXIT_FAILURE);
    }
    
  • usage(void)для NetBSD /usr/bin/telnet[ источник ]

  • usage(void)для OpenBSD /bin/ls[ источник ]

Посмотрите на альтернативы

И решить для себя, лучше они или хуже. Вы можете использовать Google CodeSearch для поиска других, например:

Как видите, разные стили между этими и BSD-системами интегрированы в инструменты, перечисленные выше. Это не значит, что вы должны следовать одному или другому. Но обычно хорошо осмотреться и согласиться на последовательное решение.

Нестандартное решение для 50 строк помощи ...

Если вам не нравится избегать 50 строк текста, вы можете просто прочитать справку из текстового файла (в виде обычного текста или, возможно, напрямую проанализировать manисходный текст, если вы его создали). Я считаю, что это довольно элегантный способ (как вы можете даже посмотреть текстовый документ), однако для основных системных программ, которые сделали бы их по сути небезопасными и привели бы к точке отказа. Другие люди будут утверждать, что это тяжело для сообщения usageили help, но это не так, как если бы они назывались в быстрых коротких циклах ...

Если есть сомнения, следуйте за гигантами.


9

Я использую stdout, потому что помощь не является ошибкой.

Если это долгая помощь в C, я попытаюсь подражать здесь документам:

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

Но большую часть времени я пишу manстраницу, используя nroff -manспециальные теги. Справка в приложении просто заключается в обращении к этой manстранице.


Но помощь не обязательно желательна для стандартного вывода, не так ли? Как насчет stdlog?
Greyfade

@greyfade: это stdlogстандарт C?
Mouviciel

@mouviciel: ... я так и думал. Я думаю, нет. C ++ имеет связанный стандартный поток ( cin, cout, cerrи clog), так что я предполагаю , что я думал , что stdlogбыло в стандарте C. Виноват.
Greyfade

2

Если я бы тебя я просто открыл источники grep, tail, cat, your_other_favorite_unix_shell_commandчтобы увидеть , как это делается там. Я уверен, что их пути хорошо продуманы и могут поддерживаться многими людьми.

О stderrили stdout. Это действительно просто, если есть ошибка - пишите stderr, если это просто информация - stdout. Например, если я запускаю ваш инструмент с неправильными параметрами, вы можете отобразить ошибку, скажем Use --help for usage, эта принадлежит stderr. Если я запускаю ваш инструмент с верной опцией --help, пожалуйста, используйте stdout.

Если вы предпочитаете, чтобы рядом с вашим кодом не было длинных строк справки, не делайте этого. #define в заголовочном файле прекрасно, но это личное предпочтение. Если бы мне пришлось читать код инструмента командной строки, я бы предпочел, чтобы его строка справки находилась внутри файла, который обрабатывает параметры, предоставленные пользователем.


2
Это не отвечает на его вопрос.
Маврик

Хм, а что с минусом? Зачем?
devmiles.com

@Mavrik: первый абзац делает.
Хайлем

1

Я использую библиотеку GNU Getopts . Для примера с помощью см. Этот пример проекта , в частности, основной метод в нижней части parser.y .

Поскольку он заключен в фигурные скобки, редактор vim, который я использую, может складывать строки, и я даже не замечаю их, когда мне это не нужно.


1

Если я использую C или предпочитаю не зависеть от библиотек Boost, то я придерживаюсь GNU getopt. В противном случае я предпочитаю параметры программы Boost, которые помогают печатать автоматически.

Я также считаю, угадывание правильного варианта одним из лучших методов, когда дело доходит до обработки опций. Я узнал об этом из Git и теперь использую то же самое в моих проектах. Он в основном использует расстояние Дамерау – Левенштейна для печати лучших совпадений, если пользователь вводит какую-то неизвестную опцию командной строки.

Я написал небольшую статью об этом, которую вы можете использовать в качестве примера.

Надеюсь, поможет :)


1

Очевидно, что написание дырочной страницы в коде cout << или printf () обременительно, особенно если вам нужно изменить и заново заполнить абзацы. Следовательно, это хорошая идея, чтобы отредактировать этот текст в отдельном файле, используя, например, emacs, где вы можете легче отформатировать текст.

Затем вы можете использовать следующий скрипт sed для преобразования этого текстового файла в допустимый файл заголовка C:

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

Затем, после #include -ing вашего заголовочного файла в ваш исходный код, вы можете просто написать свой текст, используя

cout << helpStr;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.