はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】コンソールアプリケーションで入力をパイプ(pipe)で受け取りたい

はじめに

C#でコンソールアプリケーションを作成していたとき、以下のようにパイプで入力を受け取れたらなと思いました。

# プロジェクトを利用するパターン
$ echo "Hello, World!" | dotnet run

# ビルド済みのConsole Appを利用するパターン 
$ echo "Hello, World!" | ./SampleApp

そのやり方を見つけたのでメモしておきます。

やり方

一番簡単な方法は以下のように記述することです。

while (Console.ReadLine() is { } s)
{
    Console.WriteLine($"Input: {s}");
}
$ echo "Hello, World!" | dotnet run
Input: Hello, World!

Console.ReadLineは読み取る行がなくなった(macならcontrol + c)ときにnullを返します。
Console.ReadLine メソッド (System) | Microsoft Learn

パイプを利用しないときの対策

パイプを利用するとそのまま処理が終了しますが、単純にdotnet runを実行すると入力待ちになります。(Console.ReadLineがあるので当たり前ですが...)

ただ以下のようにパイプもできるし、引数でも受け取れるようにしたくのが大体だと思います。

$ echo "Hello, World" | dotnet run
$ dotnet run "Hello, World!"

これを実現するにはConsole.IsInputRedirectedを利用します。

Gets a value that indicates whether input has been redirected from the standard input stream.

// DeepL
入力が標準入力ストリームからリダイレクトされたかどうかを示す値を取得する。

Console.IsInputRedirected Property (System) | Microsoft Learn

if (Console.IsInputRedirected)
{
    // 「echo "Hello, World!" | dotnet run」を実行した場合、標準入力はリダイレクトされている
    while (Console.ReadLine() is { } s)
    {
        Console.WriteLine($"Input(IsInputRedirected is true): {s}");
    }
}
else
{
    // 「dotnet run "Hello, World!"」を実行した場合、標準入力はリダイレクトされていない
    foreach (var arg in args)
    {
        Console.WriteLine($"Input(IsInputRedirected is false): {arg}");
    }
}