Compartilhar via


Tutorial: Introdução a System.CommandLine

Este tutorial mostra como criar um aplicativo de linha de comando .NET que usa a System.CommandLine biblioteca. Você começará criando um comando raiz simples que tem uma opção. Em seguida, você criará essa base, criando um aplicativo mais complexo que contém vários subcomandos e opções diferentes para cada comando.

Neste tutorial, você aprenderá como:

  • Crie comandos, opções e argumentos.
  • Especifique valores padrão para opções.
  • Atribua opções e argumentos a comandos.
  • Atribua uma opção recursivamente a todos os subcomandos sob um comando.
  • Trabalhar com vários níveis de subcomandos aninhados.
  • Crie aliases para comandos e opções.
  • Trabalhar com string, string[], int, bool, FileInfo e tipos de opção de enumeração.
  • Ler valores de opção no código de ação de comando.
  • Use o código personalizado para analisar e validar opções.

Pré-requisitos

Ou

  • Visual Studio com a carga de trabalho de desenvolvimento desktop do .NET instalada.

Criar o aplicativo

Crie um projeto de aplicativo de console do .NET 9 chamado "scl".

  1. Crie uma pasta chamada scl para o projeto e abra um prompt de comando na nova pasta.

  2. Execute o comando a seguir:

    dotnet new console --framework net9.0
    

Instalar o pacote System.CommandLine

  • Execute o comando a seguir:

    dotnet add package System.CommandLine
    

    Ou, no .NET 10+:

    dotnet package add System.CommandLine
    

Analisar os argumentos

Substitua o conteúdo do Program.cs pelo seguinte código:

using System.CommandLine;
using System.CommandLine.Parsing;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "The file to read and display on the console."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");
        rootCommand.Options.Add(fileOption);

        ParseResult parseResult = rootCommand.Parse(args);
        if (parseResult.Errors.Count == 0 && parseResult.GetValue(fileOption) is FileInfo parsedFile)
        {
            ReadFile(parsedFile);
            return 0;
        }
        foreach (ParseError parseError in parseResult.Errors)
        {
            Console.Error.WriteLine(parseError.Message);
        }
        return 1;
    }

    static void ReadFile(FileInfo file)
    {
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
        }
    }
}

O código anterior:

Option<FileInfo> fileOption = new("--file")
{
    Description = "The file to read and display on the console."
};

RootCommand rootCommand = new("Sample app for System.CommandLine");
rootCommand.Options.Add(fileOption);
  • args Analisa e verifica se algum valor foi fornecido para a opção--file. Nesse caso, ele chama o ReadFile método usando o valor analisado e retorna o código 0de saída:
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count == 0 && parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
    ReadFile(parsedFile);
    return 0;
}
  • Se nenhum valor for fornecido --file, ele imprimirá erros de análise disponíveis e retornará o código 1de saída:
foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;
  • O ReadFile método lê o arquivo especificado e exibe seu conteúdo no console:
static void ReadFile(FileInfo file)
{
    foreach (string line in File.ReadLines(file.FullName))
    {
        Console.WriteLine(line);
    }
}

Testar o aplicativo

Você pode usar qualquer uma das seguintes maneiras de testar ao desenvolver um aplicativo de linha de comando:

  • Execute o dotnet build comando e, em seguida, abra um prompt de comando na pasta de saída de build para executar o executável:

    dotnet build
    cd bin/Debug/net9.0
    scl --file scl.runtimeconfig.json
    
  • Use dotnet run e passe valores de opção para o aplicativo, em vez de para o comando run, incluindo-os depois de --, como no exemplo a seguir:

    dotnet run -- --file bin/Debug/net9.0/scl.runtimeconfig.json
    

(Este tutorial pressupõe que você esteja usando a primeira dessas opções.)

Quando você executa o aplicativo, ele exibe o conteúdo do arquivo especificado pela opção --file .

{
  "runtimeOptions": {
    "tfm": "net9.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "9.0.0"
    }
  }
}

Mas se você solicitar que ele exiba a ajuda usando --help, nada será impresso no console. Isso ocorre porque o aplicativo ainda não lida com o cenário em que --file não é fornecido e não ocorrerem erros de análise.

Analisar os argumentos e invocar o ParseResult

System.CommandLine permite especificar uma ação que é invocada quando um determinado símbolo (comando, diretiva ou opção) é analisado com êxito. A ação é um delegado que usa um ParseResult parâmetro e retorna um int código de saída. (Ações assíncronas também estão disponíveis). O código de saída é retornado pelo ParseResult.Invoke(InvocationConfiguration) método e pode ser usado para indicar se o comando foi executado com êxito ou não.

Substitua o conteúdo do Program.cs pelo seguinte código:

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "The file to read and display on the console."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");
        rootCommand.Options.Add(fileOption);

        rootCommand.SetAction(parseResult =>
        {
            FileInfo parsedFile = parseResult.GetValue(fileOption);
            ReadFile(parsedFile);
            return 0;
        });

        ParseResult parseResult = rootCommand.Parse(args);
        return parseResult.Invoke();
    }

    static void ReadFile(FileInfo file)
    {
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
        }
    }
}

O código anterior:

  • Especifica que ReadFile é o método que será chamado quando invocado o comando raiz.

    rootCommand.SetAction(parseResult =>
    {
        FileInfo parsedFile = parseResult.GetValue(fileOption);
        ReadFile(parsedFile);
        return 0;
    });
    
  • args Analisa e invoca o resultado:

    ParseResult parseResult = rootCommand.Parse(args);
    return parseResult.Invoke();
    

Quando você executa o aplicativo, ele exibe o conteúdo do arquivo especificado pela opção --file .

Se você solicitar que ele exiba a ajuda especificando scl --help, a seguinte saída será impressa:

Description:
  Sample app for System.CommandLine

Usage:
  scl [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information
  --file          The file to read and display on the console

RootCommand por padrão, fornece a opção Ajuda, a opção Versão e a diretiva Sugerir. O ParseResult.Invoke(InvocationConfiguration) método é responsável por invocar a ação do símbolo analisado. Pode ser a ação definida explicitamente para o comando ou a ação de ajuda definida por System.CommandLineSystem.CommandLine.Help.HelpOption.

Além disso, quando o Invoke método detecta erros de análise, ele os imprime no erro padrão, imprime a ajuda para a saída padrão e retorna 1 como o código de saída:

scl --invalid bla
Unrecognized command or argument '--invalid'.
Unrecognized command or argument 'bla'.

Adicionar um subcomando e opções

Nesta seção, você:

  • Crie mais opções.
  • Crie um subcomando.
  • Atribua as novas opções ao novo subcomando.

As novas opções permitem que o usuário final configure as cores de texto em primeiro plano e plano de fundo e a velocidade de leitura. Esses recursos serão usados para ler uma coleção de citações do tutorial do aplicativo de console Teleprompter.

  1. Copie o arquivo sampleQuotes.txt do repositório de exemplos do dotnet para o diretório do projeto.

    (Para obter informações sobre como baixar arquivos, consulte as instruções em Exemplos e tutoriais.)

  2. Abra o arquivo de projeto e adicione um <ItemGroup> elemento pouco antes da marca de fechamento </Project> :

    <ItemGroup>
      <Content Include="sampleQuotes.txt">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    

    Adicionar essa marcação faz com que o arquivo de texto seja copiado para a pasta de saída ao compilar o aplicativo. Portanto, ao executar o executável nessa pasta, você pode acessar o arquivo pelo nome sem especificar um caminho de pasta.

  3. Em Program.cs, após o código que cria a opção --file , crie opções para controlar a velocidade de leitura e as cores do texto:

    Option<int> delayOption = new("--delay")
    {
        Description = "Delay between lines, specified as milliseconds per character in a line.",
        DefaultValueFactory = parseResult => 42
    };
    Option<ConsoleColor> fgcolorOption = new("--fgcolor")
    {
        Description = "Foreground color of text displayed on the console.",
        DefaultValueFactory = parseResult => ConsoleColor.White
    };
    Option<bool> lightModeOption = new("--light-mode")
    {
        Description = "Background color of text displayed on the console: default is black, light mode is white."
    };
    
  4. Após a linha que cria o comando raiz, exclua o código que adiciona a opção --file a ele. Você a está removendo aqui porque vai adicioná-la a um novo subcomando.

  5. Depois da linha que cria o comando raiz, crie um read subcomando. Adicione as opções a esse subcomando (usando a sintaxe do inicializador de coleção em vez Options da propriedade) e adicione o subcomando ao comando raiz.

    Command readCommand = new("read", "Read and display the file.")
    {
        fileOption,
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    rootCommand.Subcommands.Add(readCommand);
    
  6. Substitua o SetAction código pelo seguinte SetAction código para o novo subcomando:

    readCommand.SetAction(parseResult => ReadFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(delayOption),
        parseResult.GetValue(fgcolorOption),
        parseResult.GetValue(lightModeOption)));
    

    Você não está mais chamando o comando raiz SetAction porque o comando raiz não precisa mais de nenhuma ação. Quando um comando tem subcomandos, normalmente você precisa especificar um dos subcomandos ao invocar um aplicativo de linha de comando.

  7. Substitua o ReadFile método de ação pelo seguinte código:

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    

O aplicativo agora tem esta aparência:

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "The file to read and display on the console."
        };

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");

        Command readCommand = new("read", "Read and display the file.")
        {
            fileOption,
            delayOption,
            fgcolorOption,
            lightModeOption
        };
        rootCommand.Subcommands.Add(readCommand);

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
}

Testar o novo subcomando

Agora, se você tentar executar o aplicativo sem especificar o subcomando, receberá uma mensagem de erro seguida por uma mensagem de ajuda que especifica o subcomando disponível.

scl --file sampleQuotes.txt
'--file' was not matched. Did you mean one of the following?
--help

Required command was not provided.
Unrecognized command or argument '--file'.
Unrecognized command or argument 'sampleQuotes.txt'.

Description:
  Sample app for System.CommandLine

Usage:
  scl [command] [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information

Commands:
  read  Read and display the file.

O texto de ajuda para subcomando read mostra que quatro opções estão disponíveis. Ele mostra valores válidos para a enumeração.

scl read -h
Description:
  Read and display the file.

Usage:
  scl read [options]

Options:
  --file <file>                                               The file to read and display on the console.
  --delay <delay>                                             Delay between lines, specified as milliseconds per
                                                              character in a line. [default: 42]
  --fgcolor                                                   Foreground color of text displayed on the console.
  <Black|Blue|Cyan|DarkBlue|DarkCyan|DarkGray|DarkGreen|Dark  [default: White]
  Magenta|DarkRed|DarkYellow|Gray|Green|Magenta|Red|White|Ye
  llow>
  --light-mode                                                Background color of text displayed on the console:
                                                              default is black, light mode is white.
  -?, -h, --help                                              Show help and usage information

Execute o subcomando read especificando apenas a opção --file e você obtém os valores padrão para as outras três opções.

scl read --file sampleQuotes.txt

O atraso padrão de 42 milissegundos por caractere causa uma velocidade de leitura lenta. Você pode acelerá-lo configurando --delay para um número menor.

scl read --file sampleQuotes.txt --delay 0

Você pode usar --fgcolor e --light-mode definir cores de texto:

scl read --file sampleQuotes.txt --fgcolor red --light-mode

Se você fornecer um valor inválido, --delayreceberá uma mensagem de erro:

scl read --file sampleQuotes.txt --delay forty-two
Cannot parse argument 'forty-two' for option '--int' as expected type 'System.Int32'.

Se você fornecer um valor inválido, --filereceberá uma exceção:

scl read --file nofile
Unhandled exception: System.IO.FileNotFoundException: Could not find file 'C:\bin\Debug\net9.0\nofile''.
File name: 'C:\bin\Debug\net9.0\nofile''

Adicionar subcomandos e validação personalizada

Esta seção cria a versão final do aplicativo. Quando terminar, o aplicativo terá os seguintes comandos e opções:

Command Opções Arguments
Comando raiz --file (recursivo)
quotes
read --delay --fgcolor --light-mode
add quote e byline
delete --search-terms

(Uma opção recursiva está disponível para o comando ao qual é atribuída e recursivamente a todos os seus subcomandos.)

Aqui está uma entrada de linha de comando de exemplo que invoca cada um dos comandos disponíveis com suas opções e argumentos:

scl quotes read --file sampleQuotes.txt --delay 40 --fgcolor red --light-mode
scl quotes add "Hello world!" "Nancy Davolio"
scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"
  1. Em Program.cs, substitua o código que cria a opção --file pelo seguinte código:

    Option<FileInfo> fileOption = new("--file")
    {
        Description = "An option whose argument is parsed as a FileInfo",
        Required = true,
        DefaultValueFactory = result =>
        {
            if (result.Tokens.Count == 0)
            {
                return new FileInfo("sampleQuotes.txt");
    
            }
            string filePath = result.Tokens.Single().Value;
            if (!File.Exists(filePath))
            {
                result.AddError("File does not exist");
                return null;
            }
            else
            {
                return new FileInfo(filePath);
            }
        }
    };
    

    Esse código usa ArgumentResult para fornecer análise personalizada, validação e tratamento de erros.

    Sem esse código, arquivos ausentes são relatados com uma exceção e rastreamento de pilha. Com esse código, apenas a mensagem de erro especificada é exibida.

    Esse código também especifica um valor padrão, e é por isso que ele define Option<T>.DefaultValueFactory como método de análise personalizado.

  2. Depois do código que cria lightModeOption, adicione opções e argumentos para os comandos add e delete:

    Option<string[]> searchTermsOption = new("--search-terms")
    {
        Description = "Strings to search for when deleting entries.",
        Required = true,
        AllowMultipleArgumentsPerToken = true
    };
    Argument<string> quoteArgument = new("quote")
    {
        Description = "Text of quote."
    };
    Argument<string> bylineArgument = new("byline")
    {
        Description = "Byline of quote."
    };
    

    A AllowMultipleArgumentsPerToken configuração permite omitir o nome da opção --search-terms ao especificar elementos na lista após a primeira. Ele torna os seguintes exemplos de entrada de linha de comando equivalentes:

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. Substitua o código que cria o comando raiz e o read comando pelo seguinte código:

    RootCommand rootCommand = new("Sample app for System.CommandLine");
    fileOption.Recursive = true;
    rootCommand.Options.Add(fileOption);
    
    Command quotesCommand = new("quotes", "Work with a file that contains quotes.");
    rootCommand.Subcommands.Add(quotesCommand);
    
    Command readCommand = new("read", "Read and display the file.")
    {
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    quotesCommand.Subcommands.Add(readCommand);
    
    Command deleteCommand = new("delete", "Delete lines from the file.");
    deleteCommand.Options.Add(searchTermsOption);
    quotesCommand.Subcommands.Add(deleteCommand);
    
    Command addCommand = new("add", "Add an entry to the file.");
    addCommand.Arguments.Add(quoteArgument);
    addCommand.Arguments.Add(bylineArgument);
    addCommand.Aliases.Add("insert");
    quotesCommand.Subcommands.Add(addCommand);
    

    Esse código faz as seguintes alterações:

    • Remove a opção --file do read comando.

    • Adiciona a opção --file como uma opção recursiva ao comando raiz.

    • Cria um quotes comando e adiciona-o ao comando raiz.

    • Adiciona o read comando ao quotes comando em vez de ao comando raiz.

    • Cria add e delete comanda e adiciona-os ao quotes comando.

    O resultado é a seguinte hierarquia de comandos:

    Comando raiz └──quotes └──read └──add └──delete

    O aplicativo agora implementa o padrão recomendado em que o comando pai (quotes) especifica uma área ou grupo e seus comandos filhos (read, add, delete) são ações.

    As opções recursivas são aplicadas ao comando e recursivamente a subcomandos. Como --file está no comando raiz, ele estará disponível automaticamente em todos os subcomandos do aplicativo.

  4. Após o SetAction código, adicione um novo SetAction código para os novos subcomandos:

    deleteCommand.SetAction(parseResult => DeleteFromFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(searchTermsOption)));
    
    addCommand.SetAction(parseResult => AddToFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(quoteArgument),
        parseResult.GetValue(bylineArgument))
        );
    

    O subcomando quotes não tem uma ação porque não é um comando folha. Os subcomandos read, add e delete são comandos folha sob quotes, e SetAction é chamado para cada um deles.

  5. Adicione as ações para add e delete.

    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");
    
        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");
    
        using StreamWriter writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
    }
    

O aplicativo concluído tem esta aparência:

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "An option whose argument is parsed as a FileInfo",
            Required = true,
            DefaultValueFactory = result =>
            {
                if (result.Tokens.Count == 0)
                {
                    return new FileInfo("sampleQuotes.txt");

                }
                string filePath = result.Tokens.Single().Value;
                if (!File.Exists(filePath))
                {
                    result.AddError("File does not exist");
                    return null;
                }
                else
                {
                    return new FileInfo(filePath);
                }
            }
        };

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

        Option<string[]> searchTermsOption = new("--search-terms")
        {
            Description = "Strings to search for when deleting entries.",
            Required = true,
            AllowMultipleArgumentsPerToken = true
        };
        Argument<string> quoteArgument = new("quote")
        {
            Description = "Text of quote."
        };
        Argument<string> bylineArgument = new("byline")
        {
            Description = "Byline of quote."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");
        fileOption.Recursive = true;
        rootCommand.Options.Add(fileOption);

        Command quotesCommand = new("quotes", "Work with a file that contains quotes.");
        rootCommand.Subcommands.Add(quotesCommand);

        Command readCommand = new("read", "Read and display the file.")
        {
            delayOption,
            fgcolorOption,
            lightModeOption
        };
        quotesCommand.Subcommands.Add(readCommand);

        Command deleteCommand = new("delete", "Delete lines from the file.");
        deleteCommand.Options.Add(searchTermsOption);
        quotesCommand.Subcommands.Add(deleteCommand);

        Command addCommand = new("add", "Add an entry to the file.");
        addCommand.Arguments.Add(quoteArgument);
        addCommand.Arguments.Add(bylineArgument);
        addCommand.Aliases.Add("insert");
        quotesCommand.Subcommands.Add(addCommand);

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        deleteCommand.SetAction(parseResult => DeleteFromFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(searchTermsOption)));

        addCommand.SetAction(parseResult => AddToFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(quoteArgument),
            parseResult.GetValue(bylineArgument))
            );

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");

        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");

        using StreamWriter writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
    }
}

Crie o projeto e, em seguida, experimente os comandos a seguir.

Envie um arquivo inexistente com comando --file o read e você obtém uma mensagem de erro em vez de uma exceção e um rastreamento de pilha:

scl quotes read --file nofile
File does not exist

Se você tentar executar o subcomando quotes, receberá uma mensagem orientando você a usar read, addou delete:

scl quotes
Required command was not provided.

Description:
  Work with a file that contains quotes.

Usage:
  scl quotes [command] [options]

Options:
  --file <file>   An option whose argument is parsed as a FileInfo [default: sampleQuotes.txt]
  -?, -h, --help  Show help and usage information

Commands:
  read                          Read and display the file.
  delete                        Delete lines from the file.
  add, insert <quote> <byline>  Add an entry to the file.

Execute o subcomando adde, em seguida, examine o final do arquivo de texto para ver o texto adicionado:

scl quotes add "Hello world!" "Nancy Davolio"

Execute o subcomando delete com cadeias de caracteres de pesquisa desde o início do arquivo e, em seguida, examine o início do arquivo de texto para ver onde o texto foi removido:

scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"

Observação

O arquivo na pasta de saída reflete as alterações dos comandos add e delete. A cópia do arquivo na pasta do projeto permanece inalterada.

Próximas etapas

Neste tutorial, você criou um aplicativo de linha de comando simples que usa System.CommandLine. Para saber mais sobre a biblioteca, confira System.CommandLine a visão geral. Para habilitar os recursos de conclusão da guia, consulte a conclusão da guia para System.CommandLine.