Лучший способ разобрать аргументы командной строки в C #?

769

При создании консольных приложений, которые принимают параметры, вы можете использовать аргументы, переданные в Main(string[] args).

В прошлом я просто проиндексировал/заципил этот массив и сделал несколько регулярных выражений для извлечения значений. Однако, когда команды становятся более сложными, синтаксический анализ может стать довольно уродливым.

Итак, меня интересует:

  • Библиотеки, которые вы используете
  • Шаблоны, которые вы используете

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

  • 0
    Предыдущее обсуждение, содержащее разделенную строку-параметры-командной строки-в-строку-в-c # , может иметь некоторые ответы.
  • 1
    Привет, извините, это немного не по теме. однако я использую «Настройки приложения» для передачи аргумента в приложение. Я обнаружил, что его довольно просто использовать, и не нужно писать разбор аргументов / файлов, и нет необходимости в дополнительной библиотеке. msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx
Показать ещё 1 комментарий
Теги:
command-line-arguments

20 ответов

340
Лучший ответ

Я бы настоятельно предложил использовать NDesk.Options (Документация) и/или Mono.Options (тот же API, другое пространство имен). Пример из документации:

bool show_help = false;
List<string> names = new List<string> ();
int repeat = 1;

var p = new OptionSet () {
    { "n|name=", "the {NAME} of someone to greet.",
       v => names.Add (v) },
    { "r|repeat=", 
       "the number of {TIMES} to repeat the greeting.\n" + 
          "this must be an integer.",
        (int v) => repeat = v },
    { "v", "increase debug message verbosity",
       v => { if (v != null) ++verbosity; } },
    { "h|help",  "show this message and exit", 
       v => show_help = v != null },
};

List<string> extra;
try {
    extra = p.Parse (args);
}
catch (OptionException e) {
    Console.Write ("greet: ");
    Console.WriteLine (e.Message);
    Console.WriteLine ("Try `greet --help' for more information.");
    return;
}
  • 14
    NDesk.options великолепен, но, похоже, на самом деле не поддерживает консольные приложения с помощью более чем одной отдельной команды. Если вы хотите, попробуйте ManyConsole, который основан на NDesk.Options: nuget.org/List/Packages/ManyConsole
  • 5
    Когда у меня есть одно приложение с несколькими различными командами, я «накладываю» наборы параметров. Возьмите mdoc ( docs.go-mono.com/index.aspx?link=man%3amdoc%281%29 ), который имеет «глобальный» OptionSet ( github.com/mono/mono/blob/master/mcs/tools/ mdoc /… ), который делегирует отдельный набор команд для каждой команды (например, github.com/mono/mono/blob/master/mcs/tools/mdoc/… )
Показать ещё 7 комментариев
189

Мне очень нравится библиотека Parser командной строки (http://commandline.codeplex.com/). Он имеет очень простой и элегантный способ настройки параметров через атрибуты:

class Options
{
    [Option("i", "input", Required = true, HelpText = "Input file to read.")]
    public string InputFile { get; set; }

    [Option(null, "length", HelpText = "The maximum number of bytes to process.")]
    public int MaximumLenght { get; set; }

    [Option("v", null, HelpText = "Print details during execution.")]
    public bool Verbose { get; set; }

    [HelpOption(HelpText = "Display this help screen.")]
    public string GetUsage()
    {
        var usage = new StringBuilder();
        usage.AppendLine("Quickstart Application 1.0");
        usage.AppendLine("Read user manual for usage instructions...");
        return usage.ToString();
    }
}
  • 6
    Это библиотека, на которой я остановился. Я пишу приложения для большой компании, которые нужно поддерживать в течение многих лет - эта библиотека постоянно обновляется с 2005 года, кажется популярной, написана людьми, активно работающими в сообществе C #, и лицензируется в стиле BSD на случай, если поддержка исчезает.
  • 0
    Я рекомендую это также. Моя единственная проблема заключалась в том, что: Задание разрешенной комбинации аргументов (например, если аргумент move должен иметь аргументы source и dest) может быть возможным для атрибутов. Но вам может быть лучше сделать это с помощью отдельной логики проверки аргументов
Показать ещё 3 комментария
50

Библиотека WPF TestApi поставляется с одним из лучших анализаторов командной строки для разработки С#. Я настоятельно рекомендую изучить его, блог Иво Манолова в API:

// EXAMPLE #2:
// Sample for parsing the following command-line:
// Test.exe /verbose /runId=10
// This sample declares a class in which the strongly-
// typed arguments are populated
public class CommandLineArguments
{
   bool? Verbose { get; set; }
   int? RunId { get; set; }
}

CommandLineArguments a = new CommandLineArguments();
CommandLineParser.ParseArguments(args, a);
  • 19
    +1. Синтаксический анализ командной строки - это то, что действительно должно исходить от поставщика (например, Microsoft), а не через сторонний инструмент, даже если поддержка поставщика идет в обход.
  • 2
    Тем не менее, принятый ответ (моно) является следующей лучшей вещью.
Показать ещё 5 комментариев
24
  • 2
    У параметров NDesk очень хороший API
  • 2
    Я добавлю еще один голос за NDesk, он работает хорошо, ненавязчив и хорошо документирован.
Показать ещё 4 комментария
14

Похоже, у всех есть свои собственные синтаксические анализаторы командной строки, и мне лучше добавить мои:).

http://bizark.codeplex.com/

Эта библиотека содержит синтаксический анализатор командной строки, который инициализирует класс со значениями из командной строки. У этого есть тонна особенностей (я строил это в течение многих лет).

Из документации...

Разбор командной строки в структуре BizArk имеет следующие ключевые особенности:

  • Автоматическая инициализация: Свойства класса автоматически устанавливаются на основе аргументов командной строки.
  • Свойства по умолчанию: Отправить в значение без указания имени свойства.
  • Преобразование значений: Использует мощный класс ConvertEx, также включенный в BizArk для преобразования значений в соответствующий тип.
  • Булевские флаги: Флаги могут быть заданы простым использованием аргумента (ex,/b для true и /b - для false) или путем добавления значения true/false, yes/no и т.д..
  • Аргументы аргументов: Просто добавьте несколько значений после имени командной строки, чтобы установить свойство, определенное как массив. Ex,/x 1 2 3 будет заполнять x массивом {1, 2, 3} (предполагая, что x определяется как массив целых чисел).
  • Алиасы командной строки:. Свойство может поддерживать несколько псевдонимов командной строки для него. Например, Help использует псевдоним?.
  • Признание частичного имени:. Вам не нужно указывать полное имя или псевдоним, достаточно просто для анализатора, чтобы устранить свойство/псевдоним из других.
  • Поддержка ClickOnce: Может инициализировать свойства, даже если они указаны как строка запроса в URL-адресе для развернутых приложений ClickOnce. Метод инициализации командной строки определит, работает ли он как ClickOnce или нет, поэтому ваш код не нуждается в изменении при его использовании.
  • Автоматически создает /? help: Это включает хорошее форматирование, которое учитывает ширину консоли.
  • Загружать/сохранять аргументы командной строки в файл: Это особенно полезно, если у вас есть несколько больших сложных наборов аргументов командной строки, которые вы хотите запускать несколько раз.
  • 2
    Я обнаружил, что анализатор командной строки BizArk намного проще и лучше, чем другие. Настоятельно рекомендуется!
13

Я написал синтаксический анализатор строки командной строки С# a while. Его at: http://www.codeplex.com/CommandLineArguments

9

CLAP (синтаксический анализатор командной строки) имеет полезный API и прекрасно документирован. Вы делаете метод, аннотируя параметры. https://github.com/adrianaisemberg/CLAP

  • 2
    Это очень просто в использовании и их сайт качается. Однако их синтаксис не очень интуитивен: myapp myverb -argname argvalue (должен иметь -argname ) или myapp -help (обычно --help ).
  • 0
    @ Каждую ночь вы можете использовать параметр IsDefault на Глаголе, чтобы его можно было опустить. Я не нашел поддержки позиционных параметров, но я использовал позиционные параметры только тогда, когда сам анализировал командную строку. Гораздо понятнее использовать именованные аргументы, за которыми следуют значения IMHO.
5

Существует множество решений этой проблемы. Для полноты и предоставления альтернативы, если кто-то желает, я добавляю этот ответ для двух полезных классов в библиотеку кодов Google.

Первым является ArgumentList, который отвечает только за синтаксический анализ параметров командной строки. Он собирает пары имя-значение, определяемые переключателями '/x: y' или '-x = y', а также собирает список "неназванных" записей. Здесь обсуждается основное , посмотреть класс здесь.

Вторая часть этого CommandInterpreter, которая создает полнофункциональное приложение из командной строки из вашего .Net-класса. В качестве примера:

using CSharpTest.Net.Commands;
static class Program
{
    static void Main(string[] args)
    {
        new CommandInterpreter(new Commands()).Run(args);
    }
    //example ‘Commands’ class:
    class Commands
    {
        public int SomeValue { get; set; }
        public void DoSomething(string svalue, int ivalue)
        { ... }

В приведенном выше примере кода вы можете запустить следующее:

Program.exe DoSomething "string value" 5

- или -

Program.exe dosomething/ivalue = 5 -svalue: "string value"

Это так просто или так сложно, как вам нужно. Вы можете просмотреть исходный код, просмотреть справку, или загрузить двоичный файл.

4

Вам может понравиться мой Rug.Cmd

Простой в использовании и расширяемый синтаксический анализатор командной строки. Ручки: Bool, Plus/Minus, String, String List, CSV, Enumeration.

Построено в '/?' режим справки.

Построено в '/??' и '/? D'.

static void Main(string[] args) 
{            
    // create the argument parser
    ArgumentParser parser = new ArgumentParser("ArgumentExample", "Example of argument parsing");

    // create the argument for a string
    StringArgument StringArg = new StringArgument("String", "Example string argument", "This argument demonstrates string arguments");

    // add the argument to the parser 
    parser.Add("/", "String", StringArg);

    // parse arguemnts
    parser.Parse(args);

    // did the parser detect a /? argument 
    if (parser.HelpMode == false) 
    {
        // was the string argument defined 
        if (StringArg.Defined == true)
        {
            // write its value
            RC.WriteLine("String argument was defined");
            RC.WriteLine(StringArg.Value);
        }
    }
}

Изменить: Это мой проект, и поэтому этот ответ не следует рассматривать как подтверждение от третьей стороны. Тем не менее, я использую его для каждой программы на основе командной строки, которую я пишу, это с открытым исходным кодом, и я надеюсь, что другие могут извлечь из этого выгоду.

  • 0
    Просто к сведению, что вам следует добавить небольшой отказ от ответственности за то, что вы связаны с проектом Rug.Cmd (как упомянуто в FAQ): stackoverflow.com/faq#promotion - Ничего страшного, так как вы продвигаете открытый исходный проект, но все же хорошо добавить отказ от ответственности;) +1 кстати ... выглядит довольно хорошо сделано.
  • 0
    Спасибо за указание на это и спасибо за +1, я сделаю все возможное, чтобы я был более откровенным в отношении моей принадлежности.
Показать ещё 1 комментарий
4

Мне нравится тот, потому что вы можете "определять правила" для аргументов, необходимых или нет,...

или если вы парень Unix, вам может понравиться порт GNU Getopt.NET.

3

Существует парсер аргументов командной строки в http://www.codeplex.com/commonlibrarynet

Он может анализировать аргументы, используя 1. атрибуты
2. Явные вызовы
3. одиночная строка из нескольких аргументов ИЛИ массив строк

Он может обрабатывать такие вещи, как следующее:

- config: Qa - startdate: ${сегодня} - регион: настройки 'New York '01

Он очень прост в использовании.

2

С# CLI - очень простая библиотека анализа аргументов аргументов командной строки, которую я написал. Это хорошо документированный и открытый исходный код.

  • 0
    Хорошо задокументированы? Где находится документация?
  • 0
    Существует внутренняя документация (т.е. в базе кода), а также внешняя документация (см. Файл Readme.mkd в папке « Documentation »).
Показать ещё 1 комментарий
2

Командные команды Powershell.

Анализ, выполненный powershell на основе атрибутов, указанных в командах, поддержка валидаций, наборов параметров, конвейерная обработка, отчет об ошибках, помощь и лучший из всех возвращающих объектов .NET для использования в других командах.

Несколько ссылок, которые я нашел полезными при запуске:

2

Недавно я столкнулся с реализацией синтаксического анализа командной строки FubuCore. Мне это очень нравится, причины:

  • он прост в использовании - хотя я не мог найти документацию для него, решение FubuCore также предоставляет проект, содержащий хороший набор тестов модулей, которые больше говорят о функциональности, чем любая документация.
  • у него есть хороший объектно-ориентированный дизайн, повторение кода или другие подобные вещи, которые я использовал в моей командной строке, анализирующей приложения.
  • он декларативный: вы в основном пишете классы для команд и наборов параметров и украшаете их атрибутами для установки различных опций (например, имя, описание, обязательный/необязательный)
  • библиотека даже печатает хороший график использования на основе этих определений

Ниже приведен простой пример того, как это использовать. Чтобы проиллюстрировать использование, я написал простую утилиту, которая имеет две команды: - добавить (добавляет объект в список - объект состоит из имени (строки), значения (int) и логического флага) - список (список всех добавленных объектов)

Прежде всего, я написал класс Command для команды 'add':

[Usage("add", "Adds an object to the list")]
[CommandDescription("Add object", Name = "add")]
public class AddCommand : FubuCommand<CommandInput>
{
    public override bool Execute(CommandInput input)
    {
        State.Objects.Add(input); // add the new object to an in-memory collection

        return true;
    }
}

Эта команда принимает экземпляр CommandInput как параметр, поэтому я определяю следующее:

public class CommandInput
{
    [RequiredUsage("add"), Description("The name of the object to add")]
    public string ObjectName { get; set; }

    [ValidUsage("add")]
    [Description("The value of the object to add")]
    public int ObjectValue { get; set; }

    [Description("Multiply the value by -1")]
    [ValidUsage("add")]
    [FlagAlias("nv")]
    public bool NegateValueFlag { get; set; }
}

Следующая команда - это "список", которая реализована следующим образом:

[Usage("list", "List the objects we have so far")]
[CommandDescription("List objects", Name = "list")]
public class ListCommand : FubuCommand<NullInput>
{
    public override bool Execute(NullInput input)
    {
        State.Objects.ForEach(Console.WriteLine);

        return false;
    }
}

Команда "list" не принимает никаких параметров, поэтому я определил для этого класс NullInput:

public class NullInput { }

Теперь все, что осталось, это связать это с методом Main(), например:

    static void Main(string[] args)
    {
        var factory = new CommandFactory();
        factory.RegisterCommands(typeof(Program).Assembly);

        var executor = new CommandExecutor(factory);

        executor.Execute(args);
    }

Программа работает как ожидалось, печатает подсказки о правильном использовании в случае, если какие-либо команды недействительны:

  ------------------------
    Available commands:
  ------------------------
     add -> Add object
    list -> List objects
  ------------------------

И пример использования команды 'add':

Usages for 'add' (Add object)
  add <objectname> [-nv]

  -------------------------------------------------
    Arguments
  -------------------------------------------------
     objectname -> The name of the object to add
    objectvalue -> The value of the object to add
  -------------------------------------------------

  -------------------------------------
    Flags
  -------------------------------------
    [-nv] -> Multiply the value by -1
  -------------------------------------
2

Мой личный фаворит http://www.codeproject.com/KB/recipes/plossum_commandline.aspx Питера Палотаса:

[CommandLineManager(ApplicationName="Hello World",
    Copyright="Copyright (c) Peter Palotas")]
class Options
{
   [CommandLineOption(Description="Displays this help text")]
   public bool Help = false;

   [CommandLineOption(Description = "Specifies the input file", MinOccurs=1)]
   public string Name
   {
      get { return mName; }
      set
      {
         if (String.IsNullOrEmpty(value))
            throw new InvalidOptionValueException(
                "The name must not be empty", false);
         mName = value;
      }
   }

   private string mName;
}
2

Это обработчик, который я написал на основе класса Novell Options.

Этот файл предназначен для консольных приложений, которые выполняют цикл стиля while (input !="exit"), например, интерактивную консоль, такую ​​как консоль FTP.

Пример использования:

static void Main(string[] args)
{
    // Setup
    CommandHandler handler = new CommandHandler();
    CommandOptions options = new CommandOptions();

    // Add some commands. Use the v syntax for passing arguments
    options.Add("show", handler.Show)
        .Add("connect", v => handler.Connect(v))
        .Add("dir", handler.Dir);

    // Read lines
    System.Console.Write(">");
    string input = System.Console.ReadLine();

    while (input != "quit" && input != "exit")
    {
        if (input == "cls" || input == "clear")
        {
            System.Console.Clear();
        }
        else
        {
            if (!string.IsNullOrEmpty(input))
            {
                if (options.Parse(input))
                {
                    System.Console.WriteLine(handler.OutputMessage);
                }
                else
                {
                    System.Console.WriteLine("I didn't understand that command");
                }

            }

        }

        System.Console.Write(">");
        input = System.Console.ReadLine();
    }
}

И источник:

/// <summary>
/// A class for parsing commands inside a tool. Based on Novell Options class (http://www.ndesk.org/Options).
/// </summary>
public class CommandOptions
{
    private Dictionary<string, Action<string[]>> _actions;
    private Dictionary<string, Action> _actionsNoParams;

    /// <summary>
    /// Initializes a new instance of the <see cref="CommandOptions"/> class.
    /// </summary>
    public CommandOptions()
    {
        _actions = new Dictionary<string, Action<string[]>>();
        _actionsNoParams = new Dictionary<string, Action>();
    }

    /// <summary>
    /// Adds a command option and an action to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action action)
    {
        _actionsNoParams.Add(name, action);
        return this;
    }

    /// <summary>
    /// Adds a command option and an action (with parameter) to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate that has one parameter - string[] args.</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action<string[]> action)
    {
        _actions.Add(name, action);
        return this;
    }

    /// <summary>
    /// Parses the text command and calls any actions associated with the command.
    /// </summary>
    /// <param name="command">The text command, e.g "show databases"</param>
    public bool Parse(string command)
    {
        if (command.IndexOf(" ") == -1)
        {
            // No params
            foreach (string key in _actionsNoParams.Keys)
            {
                if (command == key)
                {
                    _actionsNoParams[key].Invoke();
                    return true;
                }
            }
        }
        else
        {
            // Params
            foreach (string key in _actions.Keys)
            {
                if (command.StartsWith(key) && command.Length > key.Length)
                {

                    string options = command.Substring(key.Length);
                    options = options.Trim();
                    string[] parts = options.Split(' ');
                    _actions[key].Invoke(parts);
                    return true;
                }
            }
        }

        return false;
    }
}
1

"Чангисская командная строка" Parser может быть немного устаревшим, но он очень функциональный и работает очень хорошо для меня.

  • 0
    Печально, но у парсера Genghis Command Line нет документации.
  • 0
    Если вы посмотрите на источники, есть пример, который показывает варианты использования. genghis.codeplex.com/SourceControl/changeset/view/9491#73699
0

Очень простой в использовании ad hoc класс для синтаксического анализа командной строки, который поддерживает аргументы по умолчанию.

class CommandLineArgs
{
    public static CommandLineArgs I
    {
        get
        {
            return m_instance;
        }
    }

    public  string argAsString( string argName )
    {
        if (m_args.ContainsKey(argName)) {
            return m_args[argName];
        }
        else return "";
    }

    public long argAsLong(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToInt64(m_args[argName]);
        }
        else return 0;
    }

    public double argAsDouble(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToDouble(m_args[argName]);
        }
        else return 0;
    }

    public void parseArgs(string[] args, string defaultArgs )
    {
        m_args = new Dictionary<string, string>();
        parseDefaults(defaultArgs );

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private void parseDefaults(string defaultArgs )
    {
        if ( defaultArgs == "" ) return;
        string[] args = defaultArgs.Split(';');

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private Dictionary<string, string> m_args = null;
    static readonly CommandLineArgs m_instance = new CommandLineArgs();
}

class Program
{
    static void Main(string[] args)
    {
        CommandLineArgs.I.parseArgs(args, "myStringArg=defaultVal;someLong=12");
        Console.WriteLine("Arg myStringArg  : '{0}' ", CommandLineArgs.I.argAsString("myStringArg"));
        Console.WriteLine("Arg someLong     : '{0}' ", CommandLineArgs.I.argAsLong("someLong"));
    }
}
0

Пожалуйста, используйте порт .net API apache commons cli. Это отлично работает.

http://sourceforge.net/projects/dotnetcli/

и оригинальный API для концепций и внедрения

http://commons.apache.org/cli/

0

Я бы предложил библиотеку с открытым исходным кодом CSharpOptParse. Он анализирует командную строку и увлажняет пользовательский объект .NET с помощью ввода командной строки. Я всегда обращаюсь к этой библиотеке при написании приложения консоли С#.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню