How to detect if Console.In (stdin) has been redir

2019-01-01 13:37发布

I want to write a console application that have a different behavior depending if the input is coming from keyboard or from, say, a file.

Is it possible? What's the most elegant way to do it in C#?

4条回答
倾城一夜雪
2楼-- · 2019-01-01 13:54

Lorenz answer is a good beginning, but unfortunately can be used only a inspiration. There are more modes for running a console application.

  1. Standard run (in console, without any redirection)

    Everything work as expected in console.

  2. Executing with redirection from console with standard input and/or standard output redirection

    e.g.

    type input_file.txt | application.exe (in Windows), or application.exe <input_file.txt for input redirection

    (replace type with cat in Linux)

    or

    application.exe | grep pattern or application.exe >output_file.txt for output redirection

    or

    type input_file.txt | application.exe | grep pattern or application.exe <input_file.txt >output_file.txt for input and output redirection

  3. Executing with redirection from console with standard output and error output redirection

    e.g. application.exe >output_file.txt 2>error_file.txt

  4. Executing with hidden console and redirected input/output/error

    e.g. from a GUI application (console is not Visible at all)

  5. Executing with hidden console without redirection of input/output/error

Each of these mode has it's own 'features'. The Console.WindowHeight and Console.WindowWidth work in Windows for the 1st and 2nd mode in the standard way. In Linux the return value in 2nd and 3rd mode is zero. Therefore in Linux you can not detect input only redirecting.

Therefore the code from Lorenz answer can not be used for detection of redirection in all cases. The IOException when reading Console.WindowHeight or Console.WindowWidth is thrown only when there is no output to console (e.g. 3rd mode) and only for Windows.

To detect input redirection (in Windows only) use this function:

private static bool IsInputRedirected()
{
  try
  {
    if (Console.KeyAvailable)
    {
      return (false);
    }
  }
  catch (InvalidOperationException)
  {
    return (true);
  }
  return (false);
}

For all other redirection and operating systems... try to experiment how to detect them. Different console properties and functions 'work' (throw exception, or zero return values) for different modes.

Tested on Windows 7 .NET Framework 4 Client Profile and Mono JIT compiler version 4.2.1 (Debian 4.2.1.102+dfsg2-7ubuntu4).

IMPORTANT:

Do not use this function for input redirecting in Linux (detect running OS/platform, e.g. Mono for Windows), because it can cause more trouble when you falsely expect redirection and the redirection is not active.

查看更多
临风纵饮
3楼-- · 2019-01-01 13:56

Interestingly, when a pipe is open, the System.Console.WindowHeight and System.Console.WindowWidth Parameters are zero, which I found out due to several ArgumentOutOfRangeException's in code paths that did not care for the console size being zero.

Crossplatform: The behavior is the same under MS dotNET and Mono on Linux and Windows (I haven't tried it on a Mac).

When either STDIN or STDOUT are piped, the console size is set to 0. Thus building on Hans's implementation, my code is as follows:

using System;


 public static class ConsoleEx {
        public static bool IsConsoleSizeZero {
            get {
                try {
                    return (0 == (Console.WindowHeight + Console.WindowWidth));
                }
                catch (Exception exc){
                    return true;
                }
            }
        }
        public static bool IsOutputRedirected {
            get { return IsConsoleSizeZero && !Console.KeyAvailable; }
        }
        public static bool IsInputRedirected {
            get { return IsConsoleSizeZero && Console.KeyAvailable; }
        }
}

Update 2016: Added exception handling to the IsConsoleSizeZero Code to improve the usability of the code in a wider context.

The code still seems to work well, at least speaking from experience whilst using MonoDevelop / Xamarin Studio.

Related:

查看更多
呛了眼睛熬了心
4楼-- · 2019-01-01 13:59

You can find out by p/invoking the Windows FileType() API function. Here's a helper class:

using System;
using System.Runtime.InteropServices;

public static class ConsoleEx {
    public static bool IsOutputRedirected {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdout)); }
    }
    public static bool IsInputRedirected {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdin)); }
    }
    public static bool IsErrorRedirected {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stderr)); }
    }

    // P/Invoke:
    private enum FileType { Unknown, Disk, Char, Pipe };
    private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
    [DllImport("kernel32.dll")]
    private static extern FileType GetFileType(IntPtr hdl);
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetStdHandle(StdHandle std);
}

Usage:

bool inputRedirected = ConsoleEx.IsInputRedirected;

UPDATE: these methods were added to the Console class in .NET 4.5. Without attribution I might add :( Simply use the corresponding method instead of this helper class.

https://msdn.microsoft.com/en-us/library/system.console.isoutputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.isinputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.iserrorredirected.aspx

查看更多
骚的不知所云
5楼-- · 2019-01-01 14:11

Since framework 4.5 exists the property Console.IsInputRedirected. 8-)

See MSDN

https://msdn.microsoft.com/de-de/library/system.console.isinputredirected(v=vs.110).aspx

查看更多
登录 后发表回答