次の方法で共有


チュートリアル: System.CommandLineを始める

重要

System.CommandLine は現在プレビュー段階であり、このドキュメントはバージョン 2.0 ベータ 5 用です。 一部の情報は、リリース前に大幅に変更される可能性があるプレリリース製品に関連しています。 Microsoft は、ここで提供される情報に関して明示的または黙示的な保証を行いません。

このチュートリアルでは、 System.CommandLine ライブラリを使用する .NET コマンド ライン アプリを作成する方法について説明します。 まず、1 つのオプションを持つ単純なルート コマンドを作成します。 次に、そのベースを基にして、複数のサブコマンドとコマンドごとに異なるオプションを含む、より複雑なアプリを作成します。

このチュートリアルでは、以下の内容を学習します。

  • コマンド、オプション、および引数を作成します。
  • オプションの既定値を指定します。
  • コマンドにオプションと引数を割り当てます。
  • コマンドの下にあるすべてのサブコマンドにオプションを再帰的に割り当てます。
  • 多階層の入れ子になったサブコマンドを扱います。
  • コマンドとオプションのエイリアスを作成します。
  • stringstring[]intboolFileInfo、列挙型のオプションの種類を操作します。
  • コマンド アクション コードでオプション値を読み取ります。
  • カスタム コードを使用して、オプションの解析と検証を行います。

前提条件

または

アプリを作成する

"scl" という名前の .NET 9 コンソール アプリ プロジェクトを作成します。

  1. プロジェクトの scl という名前のフォルダーを作成し、新しいフォルダーでコマンド プロンプトを開きます。

  2. 次のコマンドを実行します。

    dotnet new console --framework net9.0
    

System.CommandLine パッケージをインストールする

  • 次のコマンドを実行します。

    dotnet add package System.CommandLine --prerelease
    

    .NET 10+ の場合は次のようになります:

    dotnet package add System.CommandLine --prerelease
    

    ライブラリがまだベータ版であるため、 --prerelease オプションが必要です。

引数を解析する

  1. Program.cs の内容を次のコードで置き換えます。

    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.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);
            }
        }
    }
    

前述のコード:

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を解析し、--file オプションに値が指定されたかどうかを確認します。 その場合は、解析された値を使用して ReadFile メソッドを呼び出し、終了コード 0 返します。
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
    ReadFile(parsedFile);
    return 0;
}
  • --fileに値が指定されていない場合は、使用可能な解析エラーが出力され、終了コード1返されます。
foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;
  • ReadFile メソッドは、指定したファイルを読み取り、その内容をコンソールに表示します。
static void ReadFile(FileInfo file)
{
    foreach (string line in File.ReadLines(file.FullName))
    {
        Console.WriteLine(line);
    }
}

アプリをテストする

コマンド ライン アプリの開発中にテストするには、次のいずれかの方法を使用できます。

  • dotnet build コマンドを実行し、scl/bin/Debug/net9.0 フォルダーでコマンド プロンプトを開いて実行可能ファイルを実行します。

    dotnet build
    cd bin/Debug/net9.0
    scl --file scl.runtimeconfig.json
    
  • 次の例のように、dotnet runを使用し、オプション値をrun後に含めることで、-- コマンドではなくアプリに渡します。

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

このチュートリアルでは、これらのオプションの 1 つ目を使用していることを前提としています。

アプリを実行すると、 --file オプションで指定されたファイルの内容が表示されます。

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

しかし、 --helpを提供してヘルプを表示するように依頼するとどうなりますか? --fileが提供されておらず、解析エラーがないシナリオをアプリがまだ処理していないため、コンソールには何も出力されません。

引数を解析して ParseResult を呼び出す

System.CommandLine では、特定のシンボル (コマンド、ディレクティブ、またはオプション) が正常に解析されたときに呼び出されるアクションを指定できます。 アクションは、 System.CommandLine.ParseResult パラメーターを受け取り、 int 終了コードを返すデリゲートです (非同期アクションも 使用できます)。 終了コードは System.CommandLine.Parsing.ParseResult.Invoke メソッドによって返され、コマンドが正常に実行されたかどうかを示すために使用できます。

  1. Program.cs の内容を次のコードで置き換えます。

    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);
            }
        }
    }
    

前述のコード:

  • ReadFileがルート コマンドが呼び出されたときに呼び出されるメソッドであることを指定します。

    rootCommand.SetAction(parseResult =>
    {
        FileInfo parsedFile = parseResult.GetValue(fileOption);
        ReadFile(parsedFile);
        return 0;
    });
    
  • argsを解析し、結果を呼び出します

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

アプリを実行すると、 --file オプションで指定されたファイルの内容が表示されます。

--helpを指定してヘルプを表示するように依頼するとどうなりますか?

scl --help

次の出力が出力されます。

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 conso

System.CommandLine.RootCommand 既定では、 ヘルプ オプションバージョン オプション 、Suggest ディレクティブが提供されますParseResult.Invoke メソッドは、解析されたシンボルのアクションを呼び出す役割を担います。 これは、コマンドに対して明示的に定義されたアクション、またはSystem.CommandLine.Help.HelpOptionSystem.CommandLineによって定義されたヘルプ アクションです。 さらに、解析エラーが検出されると、標準エラーに出力され、ヘルプが標準出力に出力され、終了コード 1 返されます。

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

サブコマンドとオプションを追加する

このセクションでは、次の操作を行います。

  • その他のオプションを作成します。
  • サブコマンドを作成します。
  • 新しいオプションを新しいサブコマンドに割り当てます。

新しいオプションでは、前景と背景のテキストの色と読み出し速度を構成できます。 これらの機能は、 Teleprompter コンソール アプリのチュートリアルに由来する引用符のコレクションを読み取るために使用されます。

  1. このサンプルの GitHub リポジトリからプロジェクト ディレクトリにsampleQuotes.txtファイルをコピーします。 ファイルをダウンロードする方法については、「 サンプルとチュートリアル」の手順を参照してください。

  2. プロジェクト ファイルを開き、終了<ItemGroup> タグの直前に</Project>要素を追加します。

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

    このマークアップを追加すると、アプリのビルド時にテキスト ファイルが bin/debug/net9.0 フォルダーにコピーされます。 そのため、そのフォルダーで実行可能ファイルを実行すると、フォルダー パスを指定せずに名前でファイルにアクセスできます。

  3. Program.csで、--file オプションを作成するコードの後に、読み取り速度とテキストの色を制御するオプションを作成します。

    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. ルート コマンドを作成する行の後に、 --file オプションを追加するコードを削除します。 ここで削除するのは、新しいサブコマンドに追加するためです。

  5. ルート・コマンドを作成する行の後に、 read サブコマンドを作成します。 (プロパティではなくコレクション初期化子構文を使用して) このサブコマンドにオプション Options を追加し、サブコマンドをルート コマンドに追加します。

    Command readCommand = new("read", "Read and display the file.")
    {
        fileOption,
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    rootCommand.Subcommands.Add(readCommand);
    
  6. SetAction コードを、新しいサブコマンドの次のSetAction コードに置き換えます。

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

    root コマンドにアクションが不要になったため、root コマンドで SetAction を呼び出す必要がなくなりました。 コマンドにサブコマンドがある場合は、通常、コマンド ライン アプリを呼び出すときに、いずれかのサブコマンドを指定する必要があります。

  7. ReadFileアクション メソッドを次のコードに置き換えます。

    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));
        }
    }
    

アプリは次のようになります。

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));
        }
    }
}

新しいサブコマンドをテストする

サブコマンドを指定せずにアプリを実行しようとすると、エラー メッセージの後に、使用可能なサブコマンドを指定するヘルプ メッセージが表示されます。

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.

サブコマンド read のヘルプ テキストは、4 つのオプションが使用可能であることを示しています。 列挙型の有効な値が示されています。

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

サブコマンドread--fileオプションのみを指定して実行すると、他の 3 つのオプションの既定値が取得されます。

scl read --file sampleQuotes.txt

文字ごとの既定の遅延が 42 ミリ秒の場合、読み取り速度が遅くなります。 --delayを小さい数値に設定すると、速度を上げることができます。

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

--fgcolor--light-modeを使用して、テキストの色を設定できます。

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

--delayに無効な値を指定すると、エラー メッセージが表示されます。

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

--fileに無効な値を指定すると、例外が発生します。

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''

サブコマンドとカスタム検証を追加する

このセクションでは、アプリの最終バージョンを作成します。 完了すると、アプリには次のコマンドとオプションがあります。

  • 名前が付いた recursive* オプションを持つ root コマンド --file
    • quotes 命令
      • read コマンドと、--delay--fgcolor、および --light-mode というオプション
      • add quote と という名前の引数を持つコマンドbyline
      • delete コマンドとオプション名 --search-terms

* 再帰オプションは、割り当てられているコマンドで使用でき、そのすべてのサブコマンドに再帰的に使用できます。

オプションと引数を使用して使用可能な各コマンドを呼び出すコマンド ライン入力の例を次に示します。

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. Program.csで、--file オプションを作成するコードを次のコードに置き換えます。

    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);
            }
        }
    };
    

    このコードでは、 System.CommandLine.Parsing.ArgumentResult を使用して、カスタム解析、検証、およびエラー処理を提供します。

    このコードがないと、見つからないファイルは例外とスタック トレースで報告されます。 このコードでは、指定されたエラー メッセージのみが表示されます。

    このコードでは、既定値も指定します。そのため、 DefaultValueFactory をカスタム解析メソッドに設定します。

  2. lightModeOptionを作成するコードの後に、addコマンドと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."
    };
    

    xref:System.CommandLine.Option.AllowMultipleArgumentsPerToken設定では、最初のオプションの後にリスト内の要素を指定するときに、--search-terms オプション名を省略できます。 コマンド ライン入力の次の例は同等になります。

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. ルート コマンドと read コマンドを作成するコードを次のコードに置き換えます。

    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);
    

    このコードでは、次の変更が行われます。

    • --file コマンドから read オプションを削除します。

    • --file オプションを再帰オプションとしてルート コマンドに追加します。

    • quotes コマンドを作成し、ルート コマンドに追加します。

    • ルート コマンドではなく、 read コマンドを quotes コマンドに追加します。

    • addコマンドとdelete コマンドを作成し、quotes コマンドに追加します。

    結果は、次のコマンド階層になります。

    • ルート コマンド
      • quotes
        • read
        • add
        • delete

    アプリは、親コマンド (quotes) が領域またはグループを指定し、その子コマンド (readadddelete) がアクションである推奨パターンを実装するようになりました。

    再帰オプションはコマンドに適用され、サブコマンドには再帰的に適用されます。 --fileはルート コマンド上に存在するため、アプリのすべてのサブコマンドで自動的に使用できます。

  4. SetAction コードの後に、新しいサブコマンドの新しいSetAction コードを追加します。

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

    サブコマンド quotes はリーフ コマンドではないので、アクションを持ちません。 サブコマンド readadd、および delete は、 quotesの下のリーフ コマンドであり、それぞれに対して SetAction が呼び出されます。

  5. adddeleteのアクションを追加します。

    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}");
    }
    

完成したアプリは次のようになります。

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}");
    }
}

プロジェクトをビルドし、次のコマンドを試します。

--file コマンドを使用して存在しないファイルをreadに送信すると、例外とスタック トレースの代わりにエラー メッセージが表示されます。

scl quotes read --file nofile
File does not exist

サブコマンド quotes を実行しようとすると、 readadd、または 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.

サブコマンド addを実行し、テキスト ファイルの末尾を見て、追加されたテキストを確認します。

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

サブコマンド delete ファイルの先頭から検索文字列を使用して実行し、テキスト ファイルの先頭を見て、テキストが削除された場所を確認します。

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

bin/debug/net9.0 フォルダーで実行している場合、そのフォルダーには、addコマンドとdeleteコマンドからの変更を含むファイルがあります。 プロジェクト フォルダー内のファイルのコピーは変更されません。

次のステップ

このチュートリアルでは、 System.CommandLineを使用する簡単なコマンド ライン アプリを作成しました。 ライブラリの詳細については、 System.CommandLine の概要を参照してください。