05 November 2025 Console, .NET, Windows Robert Muehsig

Confession time:
It’s almost embarrassing to admit this — but after years of writing .NET code and using the terminal daily, I recently discovered that you can redirect the error output of a program using 2>.

So I decided to write this post — partly as a note to my future self, and partly for anyone else who’s ever thought:
“Wait… why are there two output streams?”

Overview

When you build console applications or CLI tools in .NET, sooner or later you’ll encounter these basic “input”/”output”-streams:

  • stdin — standard input (like keyboard, files, or pipes) or in C# Console.In, Console.ReadLine()
  • stdout — standard output or in C# Console.Out, Console.WriteLine()

Besides the “standard output” there is a special output just for errors or warnings:

  • stderr - Error or diagnostic messages or in C# Console.Error, Console.Error.WriteLine()

Having a dedicated error stream means your program can separate data output (for other programs or files) from diagnostic messages (for humans).

A Simple Example

Let’s build a small C# program that reads from stdin, writes to stdout, and reports problems on stderr.

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("== Start ==");

        string? line;
        int lineCount = 0;

        // Read from stdin
        while ((line = Console.ReadLine()) != null)
        {
            lineCount++;

            // Normal output
            Console.WriteLine($"[{lineCount}] {line}");

            // Print errors separately
            if (line.Contains("error", StringComparison.OrdinalIgnoreCase))
            {
                Console.Error.WriteLine($"Line {lineCount}: contains the word 'error'");
            }
        }

        Console.WriteLine("== End ==");
    }
}

When you run it and type some lines and include the word error, the output will look like this:

== Start ==
[1] Hello
[2] error found
Line 2: contains the word 'error'
[3] test
== End ==

Why 2> means stderr

If you run the same app like this with the same input:

.\SampleConsoleApp.exe 2> err.txt

The Line 2: contains the word 'error' will be redirected into the err.txt.

Input as file

Let’s say you have a file that should be used as an input, then you could invoke the program like this:

.\SampleConsoleApp.exe < input.txt

Input with pipes

You can also use the | operator to use this as input stream:

"error" | .\SampleConsoleApp.exe 2> err.txt

Final thoughts

The standard streams are one of those Unix-era ideas that aged perfectly. They make it easy to connect programs like Lego bricks — and .NET gives you full access to them.

Hope this helps!


Written by Robert Muehsig

Software Developer - from Saxony, Germany - working on primedocs.io. Microsoft MVP & Web Geek.
Other Projects: KnowYourStack.com | ExpensiveMeeting | EinKofferVollerReisen.de